使用线程池(5)
在线程池中使用等待事件处理器及超时
简介
当有大量的线程必须处于阻塞状态等待一些多线程事件发信号时,这种方法非常有效。异步操作函数和回调函数在不同的线程上,只有异步操作函数发出信号或者发生超时,被阻塞的回调函数的线程上的操作才会执行。
以下是代码实践:
using System;
using System.Threading;
namespace 在线程池中使用等待事件处理器及超时
{
internal class Program
{
private static void Main()
{
RunOperations(TimeSpan.FromSeconds(5));//设置为5秒超时
RunOperations(TimeSpan.FromSeconds(7));//设置为7秒超时
Console.ReadKey();
}
private static void RunOperations(TimeSpan workerOperationTimeout)
{
using (var evt=new ManualResetEvent(false))
using( var cts=new CancellationTokenSource())
{
//注意:异步操作函数和回调函数不在同一个线程
Console.WriteLine("Registering timeout operation...");
//注册一个委托并且指定超时
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);
}
}
//异步操作函数
private static void WorkerOperation(CancellationToken token,ManualResetEvent evt)
{
Console.WriteLine("WorkerOperation thread id: {0}",Thread.CurrentThread.ManagedThreadId);
for (var i = 0; i < 6; i++)//轮询6秒
{
if (token.IsCancellationRequested)
{
return;
}
Thread.Sleep(TimeSpan.FromSeconds(1));
}
evt.Set();//成功完成后设置,一旦超时则不再执行此步。
}
//事件处理器收到信号或发生超时,调用此回调函数,此函数被放到线程池的队列中。
private static void WorkerOperationWait(CancellationTokenSource cts, bool isTimeout)
{
Console.WriteLine("WorkerOperationWait thread id: {0}", Thread.CurrentThread.ManagedThreadId);
if (isTimeout)//发生超时
{
cts.Cancel();
Console.WriteLine("Worker operation time out and was canceled");
}
else//未发生超时,即事件处理器收到信号
{
Console.WriteLine("Worker operation succeded.");
}
}
}
}
总结
ThreadPool.RegisterWaitForSingleObject方法允许我们将回调函数放入线程池队列中,当提供的等待事件处理器收到信号或发生超时时,该回调函数才会被调用,然后可以在回调函数中取消异步操作函数中的操作,实现线程池中的操作的超时功能。感觉理解起来有点绕,要慢慢消化!
备注:学习《Multithreading in C# 5.0 Cookbook》Eugene Agafonov著的总结,以备日后查询。