使用线程池(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著的总结,以备日后查询。

相关内容推荐