タスクをxミリ秒で開始するようにスケジュールし、開始前に(またはタスクの開始時に)キャンセルできるようにします。
最初の試みは次のようになります
var _cancelationTokenSource = new CancellationTokenSource();
var token = _cancelationTokenSource.Token;
Task.Factory.StartNew(() =>
{
token.ThrowIfCancellationRequested();
Thread.Sleep(100);
token.ThrowIfCancellationRequested();
}).ContinueWith(t =>
{
token.ThrowIfCancellationRequested();
DoWork();
token.ThrowIfCancellationRequested();
}, token);
しかし、スリープ中にスレッドを使い果たし、その間にスレッドをキャンセルする可能性があるため、より良い方法があるはずだと感じています。
私の他のオプションは何ですか?
Damien_The_Unbeliever前述 のように、非同期CTPにはTask.Delay
。幸いなことに、Reflectorがあります。
public static class TaskEx
{
static readonly Task _sPreCompletedTask = GetCompletedTask();
static readonly Task _sPreCanceledTask = GetPreCanceledTask();
public static Task Delay(int dueTimeMs, CancellationToken cancellationToken)
{
if (dueTimeMs < -1)
throw new ArgumentOutOfRangeException("dueTimeMs", "Invalid due time");
if (cancellationToken.IsCancellationRequested)
return _sPreCanceledTask;
if (dueTimeMs == 0)
return _sPreCompletedTask;
var tcs = new TaskCompletionSource<object>();
var ctr = new CancellationTokenRegistration();
var timer = new Timer(delegate(object self)
{
ctr.Dispose();
((Timer)self).Dispose();
tcs.TrySetResult(null);
});
if (cancellationToken.CanBeCanceled)
ctr = cancellationToken.Register(delegate
{
timer.Dispose();
tcs.TrySetCanceled();
});
timer.Change(dueTimeMs, -1);
return tcs.Task;
}
private static Task GetPreCanceledTask()
{
var source = new TaskCompletionSource<object>();
source.TrySetCanceled();
return source.Task;
}
private static Task GetCompletedTask()
{
var source = new TaskCompletionSource<object>();
source.TrySetResult(null);
return source.Task;
}
}
.NET 4.5がリリースされて以来、タスクを遅延させる非常に簡単な組み込み方法があります。単に Task.Delay()
を使用してください。舞台裏では、 ohadsc decompiled という実装を使用しています。
将来の正解はおそらくTask.Delay
。ただし、現在は Async CTP を介してのみ使用できます(CTPでは、TaskではなくTaskExにあります)。
残念ながら、それはCTPにのみあるため、ドキュメントへのリンクもあまりありません。
私はこれをテストしていませんが、最初の「遅延」タスクを作成するか、遅延後に続行するラッパーメソッドでの最初のパスです。問題が見つかった場合は、お気軽に修正してください。
public static Task StartDelayTask(int delay, CancellationToken token)
{
var source = new TaskCompletionSource<Object>();
Timer timer = null;
timer = new Timer(s =>
{
source.TrySetResult(null);
timer.Dispose();
}, null, delay, -1);
token.Register(() => source.TrySetCanceled());
return source.Task;
}
public static Task ContinueAfterDelay
(this Task task,
int delay, Action<Task> continuation,
CancellationToken token)
{
var source = new TaskCompletionSource<Object>();
Timer timer = null;
var startTimer = new Action<Task>(t =>
{
timer = new Timer(s =>
{
source.TrySetResult(null);
timer.Dispose();
},null,delay,-1);
});
task.ContinueWith
(startTimer,
token,
TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.Current);
token.Register(() => source.TrySetCanceled());
return source.Task.ContinueWith(continuation, token);
}
"。NET 4サンプルによる並列プログラミング" のTaskFactoryExtensions_Delayedを見てください。
Token.WaitHandle.WaitOne(int32ミリ秒)オーバーロードメソッドを使用して、タスクを待機するミリ秒数を指定できます。ただし、指定された時間が経過するかトークンがキャンセルされるまでスレッドをブロックするThread.Sleep(xxx)とToken.WaitHandle.WaitOne(xxx)の重要な違い。
ここに例があります
void Main()
{
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
var task = Task.Factory.StartNew(() =>
{
// wait for 5 seconds or user hit Enter key cancel the task
token.WaitHandle.WaitOne(5000);
token.ThrowIfCancellationRequested();
Console.WriteLine("Task started its work");
});
Console.WriteLine("Press 'Enter' key to cancel your task");
Console.Read();
tokenSource.Cancel();
}