如何“睡眠”,直到在.NET 4.0中请求超时或取消
什么是睡眠一定时间的最佳方式,但能够被CancellationToken的IsCancellationRequested中断? 
我正在寻找一个在.NET 4.0中工作的解决scheme。
我想写
 void MyFunc (CancellationToken ct) { //... // simulate some long lasting operation that should be cancelable Thread.Sleep(TimeSpan.FromMilliseconds(10000), ct); } 
	
我只是在这里博客:
CancellationToken和Thread.Sleep
简而言之:
 var cancelled = token.WaitHandle.WaitOne(TimeSpan.FromSeconds(5)); 
在你的情况下:
 void MyFunc (CancellationToken ct) { //... // simulate some long lasting operation that should be cancelable var cancelled = ct.WaitHandle.WaitOne(TimeSpan.FromSeconds(10)); } 
或者,我认为这很清楚:
 Task.Delay(waitTimeInMs, cancellationToken).Wait(); 
要在一段时间后取消asynchronous操作,同时仍然可以手动取消操作,请使用类似以下内容的操作
 CancellationTokenSource cts = new CancellationTokenSource(); CancellationToken token = cts.Token; cts.CancelAfter(5000); 
 这将导致五秒钟后取消。 要取消操作,您只需将token传递给asynchronous方法,并使用token.ThrowifCancellationRequested()方法,您可以在其中设置一个事件处理函数来激发cts.Cancel() 。 
所以一个完整的例子是:
 CancellationTokenSource cts = new CancellationTokenSource(); CancellationToken token = cts.Token; cts.CancelAfter(5000); // Set up the event handler on some button. if (cancelSource != null) { cancelHandler = delegate { Cancel(cts); }; stopButton.Click -= cancelHandler; stopButton.Click += cancelHandler; } // Now launch the method. SomeMethodAsync(token); 
 其中stopButton是您单击以取消正在运行的任务的button 
 private void Cancel(CancellationTokenSource cts) { cts.Cancel(); } 
该方法被定义为
 SomeMethodAsync(CancellationToken token) { Task t = Task.Factory.StartNew(() => { msTimeout = 5000; Pump(token); }, token, TaskCreationOptions.None, TaskScheduler.Default); } 
现在,为了使您能够使用线程,并且使用户取消,您需要编写一个“抽取”方法
 int msTimeout; bool timeLimitReached = false; private void Pump(CancellationToken token) { DateTime now = DateTime.Now; System.Timer t = new System.Timer(100); t.Elapsed -= t_Elapsed; t.Elapsed += t_Elapsed; t.Start(); while(!timeLimitReached) { Thread.Sleep(250); token.ThrowIfCancellationRequested(); } } void t_Elapsed(object sender, ElapsedEventArgs e) { TimeSpan elapsed = DateTime.Now - this.readyUpInitialised; if (elapsed > msTimeout) { timeLimitReached = true; t.Stop(); t.Dispose(); } } 
 请注意, SomeAsyncMethod将直接返回给调用者。 要阻止呼叫者,也必须在呼叫层次结构中移动Task 。 
到目前为止,我发现的最佳解决scheme是:
 void MyFunc(CancellationToken ct) { //... var timedOut = WaitHandle.WaitAny(new[] { ct.WaitHandle }, TimeSpan.FromMilliseconds(2000)) == WaitHandle.WaitTimeout; var cancelled = ! timedOut; } 
更新:
迄今为止最好的解决scheme是被接受的答案 。