近来在学习Eugene Agafonov编写的《C#多线程编程实战》(译),做些笔记也顺便分享一下^-^
using System;
using System.Threading;
namespace 在线程池中使用等待事件处理器及超时
{
class Program
{
static void Main(string[] args)
{
RunOperation(TimeSpan.FromSeconds(5));
RunOperation(TimeSpan.FromSeconds(7));
Console.ReadKey();
}
static void RunOperation(TimeSpan workerOperationTimeout)
{
using (var evt = new ManualResetEvent(false))
using (var cts=new CancellationTokenSource())
{
Console.WriteLine("Registering timeout operations...");
var worker = ThreadPool.RegisterWaitForSingleObject(evt, (state, isTimeOut) => WorkerOperationWait(cts, isTimeOut), null, workerOperationTimeout, true);
Console.WriteLine("Starting long running operation...");
ThreadPool.QueueUserWorkItem(_ => WorkerOperation(cts.Token, evt));
Thread.Sleep(workerOperationTimeout.Add(TimeSpan.FromSeconds(2)));
worker.Unregister(evt);
}
}
static void WorkerOperation(CancellationToken token,ManualResetEvent evt)
{
for (int i = 0; i < 6; i++)
{
if (token.IsCancellationRequested)
{
return;
}
Thread.Sleep(TimeSpan.FromSeconds(1));
}
evt.Set();
}
static void WorkerOperationWait(CancellationTokenSource cts,bool isTimeOut)
{
if (isTimeOut)
{
cts.Cancel();
Console.WriteLine("Worker operation timed out and was canceled.");
}
else
{
Console.WriteLine("Worker operation succeded.");
}
}
}
}
程序运行结果如下:
线程池还有一个有用的方法:ThreadPool.RegisterWaitForSingleObject.该方法允许我们将回调函数放人线程池中的队列中。当提供的等待事件处理器收到信号或发生超时时,该回调函数将被调用。这允许我们为线程池中的操作实现超时功能。
首先按顺序向线程池中放入一个耗时长的操作。它运行6秒钟然后一旦成功完成,会设置一个ManualResetEvent信号类。其他的情况下,比如需要取消操作,则该操作会被丢弃。
然后我们注册第二个异步操作。当从ManualResetEvent对象接受到一个信号后,该异步操作会被调用。如果第一个操作顺利完成,会设置该信号量。另一种情况是第一个操作还未完成就已经超时。如果发生了该情况,我们会使用CancellationToken来取消第一个操作。
最后,为操作提供5秒钟的超时时间是不够的。这是因为操作会花费6秒来完成,只能取消该操作。所以如果提供7秒的超时时间是可行的,该操作会顺利完成。