等待CancellationToken取消请求

时间:2016-10-09 10:56:48

标签: c# task-parallel-library

如何在请求取消之前暂停执行?

var cts = new CancellationTokenSource();

Task.Run(() =>
{
    // Wait for the Cancel...

    Console.WriteLine("Canceled!");
});

Console.ReadKey();

cts.Cancel();

Console.ReadKey();

2 个答案:

答案 0 :(得分:5)

您可以使用WaitHandle同步等待:

static void Main()
{
    var cts = new CancellationTokenSource();

    Task.Run(() =>
    {
        // Wait for the Cancel...

        cts.Token.WaitHandle.WaitOne();

        Console.WriteLine("Canceled!");
    });

    Console.ReadKey();

    cts.Cancel();

    Console.ReadKey();
}

那就是说,"阻止一个线程,直到某些东西被取消"这是一个非常罕见的情况,因此您可能会使用错误的工具来完成这项工作。如果您需要等待某些事情(特别是取消),您可以使用TaskCompletionSource代替。如果您需要对取消做出反应,可以使用CancellationToken.Register附加回调(因此避免阻止线程)。

答案 1 :(得分:3)

CancellationTokenSource在内部使用ManualResetEvent,您可以等待公开的WaitHandle暂停执行,直到设置为止。

var cts = new CancellationTokenSource();

Task.Run(() =>
{
    WaitHandle.WaitAny(new[] { cts.Token.WaitHandle });

    Console.WriteLine("Canceled!");
});

Console.ReadKey();

cts.Cancel();

Console.ReadKey();

这是CancellationTokenSource中定义的WaitHandle:

ManualResetEvent mre = new ManualResetEvent(false);
if (Interlocked.CompareExchange(ref m_kernelEvent, mre, null) != null)
{    
    ((IDisposable)mre).Dispose();
}

// There is a ---- between checking IsCancellationRequested and setting the event.
// However, at this point, the kernel object definitely exists and the cases are:
//   1. if IsCancellationRequested = true, then we will call Set()
//   2. if IsCancellationRequested = false, then NotifyCancellation will see that the event exists, and will call Set().
if (IsCancellationRequested)
    m_kernelEvent.Set();

return m_kernelEvent;

Token只返回源的句柄(有一个引用它的内部变量)。

另一种选择是注册Token回调并使用您自己的ManualResetEvent

var cts = new CancellationTokenSource();

Task.Run(() =>
{
    var mre = new ManualResetEvent(false);

    var registration = cts.Token.Register(() => mre.Set());

    using (registration)
    {
        mre.WaitOne();

        Console.WriteLine("Canceled!");
    }
});

Console.ReadKey();

cts.Cancel();

Console.ReadKey();

示例:https://blogs.msdn.microsoft.com/pfxteam/2009/05/22/net-4-cancellation-framework/