C#多线程编程笔记(3.3)-在线程池中使用等待事件处理器及超时

近来在学习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秒的超时时间是可行的,该操作会顺利完成。

猜你喜欢

转载自blog.csdn.net/qq_35445058/article/details/80780736