Skip to content

C# 多线程 03-使用线程池 05-在线程中使用等待事件处理器及超时

🏷️ 《C# 多线程》

本节将通过一个示例来展示如何在线程池中取消异步操作。

csharp
/// <summary>
/// 在线程中使用等待事件处理器及超时
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
    RunOperations(TimeSpan.FromSeconds(5));
    RunOperations(TimeSpan.FromSeconds(7));
}

static void RunOperations(TimeSpan workerOperationTimeout)
{
    using (var evt = new ManualResetEvent(false))
    using (var cts = new CancellationTokenSource())
    {
        Console.WriteLine($"注册一个超时操作...");
        // 该方法允许我们将回调函数放入线程池中的队列中。
        // 当提供的等待时间处理器收到信号或发生超时时,该回调函数将被调用。
        // 第一个参数是等待对象(System.Threading.WaitHandle)
        // 第二个参数是回调函数
        // 第四个参数是超时事件
        // 第五个参数为 true,表示仅执行一次
        var worker = ThreadPool.RegisterWaitForSingleObject(evt,
            (state, isTimeOut) => WorkerOperationWait(cts, isTimeOut),
            null,
            workerOperationTimeout,
            true);

        Console.WriteLine("开始执行一个长操作");
        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++)
    {
        // 判断 token 是否已取消
        if (token.IsCancellationRequested)
        {
            return;
        }
        Thread.Sleep(TimeSpan.FromSeconds(1));
    }
    // 6 秒后发送事件结束信号
    evt.Set();
}

static void WorkerOperationWait(CancellationTokenSource cts, bool isTimeOut)
{
    if (isTimeOut)
    {
        // 如果操作超时,则发送取消信号
        cts.Cancel();
        Console.WriteLine("操作超时且被取消");
    } else
    {
        Console.WriteLine("操作执行成功");
    }
}

打印结果

注册一个超时操作...
开始执行一个长操作
操作超时且被取消
注册一个超时操作...
开始执行一个长操作
操作执行成功


ThreadPool.RegisterWaitForSingleObject 方法的定义如下:

csharp
//
// 摘要:
//     注册一个等待 System.Threading.WaitHandle 的委托,并指定一个 System.TimeSpan 值来表示超时时间。
//
// 参数:
//   waitObject:
//     要注册的 System.Threading.WaitHandle。使用 System.Threading.WaitHandle 而非 System.Threading.Mutex。
//
//   callBack:
//     向 waitObject 参数发出信号时调用的 System.Threading.WaitOrTimerCallback 委托。
//
//   state:
//     传递给委托的对象。
//
//   timeout:
//     System.TimeSpan 表示的超时时间。如果 timeout 为 0(零),则函数将测试对象的状态并立即返回。如果 timeout 为 -1,则函数的超时间隔永远不过期。
//
//   executeOnlyOnce:
//     如果为 true,表示在调用了委托后,线程将不再在 waitObject 参数上等待;如果为 false,表示每次完成等待操作后都重置计时器,直到注销等待。
//
// 返回结果:
//     封装本机句柄的 System.Threading.RegisteredWaitHandle。
//
// 异常:
//   T:System.ArgumentOutOfRangeException:
//     timeout 参数是小于 -1。
//
//   T:System.NotSupportedException:
//     timeout 参数是否大于 System.Int32.MaxValue。
[SecuritySafeCritical]
public static RegisteredWaitHandle RegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, TimeSpan timeout, bool executeOnlyOnce);