c# - 为什么CancellationTokenSource挂了一个应用

标签 c# .net asynchronous task

这是一个挂起且永不结束的简单代码片段:

public static void Main()
{
    using (var cancellationTokenSource = new CancellationTokenSource())
    {
        Console.CancelKeyPress += (_, __) => 
            cancellationTokenSource.Cancel();
        while (!cancellationTokenSource.Token.WaitHandle.WaitOne(1000))
        {
            Console.WriteLine("Still running...");
        }
        Console.WriteLine("Cancellation is requested. Trying to dispose cancellation token...");
    }
    Console.WriteLine("Just before close");
}

问题是 Just before close 行永远不会执行。我的第一个想法是“可能是因为 KeyPress 关闭了”,所以我按以下方式重写了它:

public static void Main()
{
    using (var cancellationTokenSource = new CancellationTokenSource())
    {
        void Foo(object sender, ConsoleCancelEventArgs consoleCancelEventArgs)
        {
            cancellationTokenSource.Cancel();
        }
        Console.CancelKeyPress += Foo;
        while (!cancellationTokenSource.Token.WaitHandle.WaitOne(1000))
        {
            Console.WriteLine("Still running...");
        }
        Console.WriteLine("Cancellation is requested. Unsubscribing...");
        Console.CancelKeyPress -= Foo;
        Console.WriteLine("Cancellation is requested. Trying to dispose cancellation token...");
    }
    Console.WriteLine("Just before close");
}

但现在它卡在 Unsubscribing 中风...

知道为什么会这样吗?我想运行一些后台任务并等待它在控制台应用程序中完成,但由于上述原因,我的应用程序刚刚损坏。

最佳答案

问题不是您的取消 token ,而是您选择使用 CancelKeyPress 进行测试的事实。当此事件发生时,您将获得 ConsoleCancelEventArgs,它有一个 Cancel property :

Gets or sets a value that indicates whether simultaneously pressing the Control modifier key and the C console key (Ctrl+C) or the Ctrl+Break keys terminates the current process. The default is false, which terminates the current process.

由于您没有将其设置为 true,您的应用程序将在事件处理程序完成运行后终止。根据当时发生的具体情况,似乎有时取消 token 有时间跳出 while 循环,有时却没有:

test runs

您的原始代码可以修复如下:

public static void Main()
{
    using (var cancellationTokenSource = new CancellationTokenSource())
    {
        Console.CancelKeyPress += (_, ccea) => {
            cancellationTokenSource.Cancel();
            ccea.Cancel = true; //cancel the cancel.  There's too many cancels!
        };
        while (!cancellationTokenSource.Token.WaitHandle.WaitOne(1000))
        {
            Console.WriteLine("Still running...");
        }
        Console.WriteLine("Cancellation is requested. Trying to dispose cancellation token...");
    }
    Console.WriteLine("Just before close");
}

关于c# - 为什么CancellationTokenSource挂了一个应用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49537037/

相关文章:

c# - 将字节数组发送到 WCF 服务

asp.net - MVC3 和 Entity Framework

c# - 杀死父进程时杀死子进程

ios - 更新 block 内的 UI

c# - 在 C# 中编码(marshal) C++ "char**"

c# - 多线程代码卡在 Form.ShowDialog() 语句中

c# - 更改自定义优先级队列中的优先级

c# - 调用套接字的ReceiveAsync()调用后,接收到的数据缓冲区始终为空吗?

asynchronous - 如何让fluent-ffmpeg在执行下一行代码之前完成渲染?

javascript - 如何通过 ClearScript 将 AdWords 公开给 JavaScript?