c# - 捕获 CancelKeyPress 以在安全点停止异步控制台应用程序

标签 c# asynchronous console console-application cancellation

我正在开发一个小型实用程序控制台应用程序,内置于 C# 7.1(支持 async Main)。

该应用程序采用几个输入命令之一,然后启动一个长时间运行的过程,该过程迭代数以万计的项目,处理每个项目。

我希望能够随时取消此过程(使用 CTRL+C),尽管程序不应该立即取消,而是应该完成当前迭代,然后停止。

这是迄今为止我所拥有的缩短版本。

private static bool _cancel;    

private static async Task Main(string[] args)
{
    Console.CancelKeyPress += (sender, eventArgs) =>
                                      {
                                          eventArgs.Cancel = true;                                              _logger("Migration will be stopped after the current record has been completed.\n");
                                          _cancel = true;
                                      };

    while (!_cancel)
    {
        var input = Console.ReadLine();

        // handle the various input commands
    }
}

在运行(可选)长时间运行进程的方法中,有一个逻辑检查这个全局 _cancel多变的:
private static async Task RunPersonMigration(Order order)
{
    var nextPerson = // ...
    while (nextPerson.IsValid)
    {
        // business logic

        if (_cancel)
        {
            _logger("Person migration stopped by user.\n");
            return;
        }

        nextPerson = // ...
    }
}

但是,每当我按 CTRL+C 时,Visual Studio 调试器都会要求我定位程序集,而且每次通常都是不同的程序集。例如,我被要求找到 waithandle.cs 和 thread.cs。因为我无法找到此类文件,正在运行的调试过程突然停止。

我永远看不到是哪一行导致了问题,而且没有多少断点有帮助。

基本上,我正在尝试使用 CTRL+C 退出长时间运行的进程而不退出控制台应用程序。

谁能告诉我应该如何正确处理在我选择的点取消长时间运行的控制台进程?

更新:
如果我更新我的 CancelKeyPress 代表...
Console.CancelKeyPress += (sender, eventArgs) =>
                                  {
                                      **eventArgs.Cancel = true;**                                              _logger("Migration will be stopped after the current record has been completed.\n");
                                      _cancel = true;
                                  };

那么这会阻止程序崩溃到关闭,但我仍然希望能够捕获 CTRL+C 并将其用作退出长时间运行的进程而不退出控制台应用程序本身的一种方式。这甚至可能吗?

最佳答案

使用 CancellationToken 的工作示例, 可以向下传递:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp
{
    class Program
    {
        // Cancellation Tokens - https://docs.microsoft.com/en-us/previous-versions/dd997289(v=vs.110)
        private static readonly CancellationTokenSource canToken = new CancellationTokenSource();

        static async Task Main(string[] args)
        {
            Console.WriteLine("Application has started. Ctrl-C to end");

            Console.CancelKeyPress += (sender, eventArgs) =>
            {
                Console.WriteLine("Cancel event triggered");
                canToken.Cancel();
                eventArgs.Cancel = true;
            };

            await Worker();

            Console.WriteLine("Now shutting down");
            await Task.Delay(1000);
        }

        async static Task Worker()
        {
            while (!canToken.IsCancellationRequested)
            {
                // do work       
                Console.WriteLine("Worker is working");
                await Task.Delay(1000); // arbitrary delay
            }
        }
    }
}

关于c# - 捕获 CancelKeyPress 以在安全点停止异步控制台应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48222797/

相关文章:

ios - 如何在到达返回语句之前快速修改异步 URLrequest 中的数据

c# - 带有 IN 参数的 SqlCommand 问题

c# - 如何在 C# 中获取两个字节并将它们组合成一个 UInt16?

c# - ConcurrentQueue 和 Parallel.ForEach

javascript - 语法错误: Unexpected Token async()

javascript - 在后端或前端列出一个集合

c++ - 如何防止控制台窗口超出屏幕?

linux - 使用 bash 打开和保存更改

c# - 无法创建组件 .. 类型未标记为可序列化

javascript - 数组显示其长度为 0 但控制台显示否则