You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#控制台多可取消任务:单任务异常时如何取消其他任务?

实现单个任务异常时取消其他任务的C#控制台应用方案

需求回顾

  • 运行多个并行任务
  • 支持Ctrl+C触发全局取消
  • 单个任务抛出未处理异常时,立即取消所有其他任务

你的现有代码已经实现了Ctrl+C的取消逻辑,但缺少异常触发取消的机制——当某个任务抛出异常时,Task.WhenAll会立即抛出第一个异常,但其他任务仍会继续运行,直到完成或被外部取消。下面是修改后的完整解决方案:

修改后的代码

public static async Task<int> Main()
{
    using CancellationTokenSource cts = new();

    Console.CancelKeyPress += (sender, e) =>
    {
        e.Cancel = true;
        cts.Cancel();
    };

    try
    {
        // 包装任务,统一处理异常与取消逻辑
        async Task WrappedTask(Func<CancellationToken, Task> taskLogic, CancellationToken token)
        {
            try
            {
                await taskLogic(token);
            }
            catch (OperationCanceledException)
            {
                // 取消异常直接抛出,不额外处理
                throw;
            }
            catch (Exception)
            {
                // 捕获到业务异常时,立即触发全局取消
                cts.Cancel();
                // 重新抛出异常,让上层catch处理退出逻辑
                throw;
            }
        }

        var taskA = Task.Run(() => WrappedTask(async token =>
        {
            // 任务A示例逻辑:定期检查取消令牌
            for (int i = 0; i < 10; i++)
            {
                token.ThrowIfCancellationRequested();
                Console.WriteLine("Task A 运行中...");
                await Task.Delay(1000, token);
            }
            // 取消注释可模拟异常
            // throw new InvalidOperationException("Task A 执行失败!");
        }, cts.Token), cts.Token);

        var taskB = Task.Run(() => WrappedTask(async token =>
        {
            for (int i = 0; i < 10; i++)
            {
                token.ThrowIfCancellationRequested();
                Console.WriteLine("Task B 运行中...");
                await Task.Delay(1000, token);
            }
        }, cts.Token), cts.Token);

        var taskC = Task.Run(() => WrappedTask(async token =>
        {
            for (int i = 0; i < 10; i++)
            {
                token.ThrowIfCancellationRequested();
                Console.WriteLine("Task C 运行中...");
                await Task.Delay(1000, token);
            }
        }, cts.Token), cts.Token);

        await Task.WhenAll(taskA, taskB, taskC);
        return 0;
    }
    catch (OperationCanceledException)
    {
        Console.WriteLine("所有任务已取消");
        return 0;
    }
    catch (Exception ex)
    {
        Console.WriteLine($"发生未处理异常: {ex.Message}");
        return 1;
    }
}

核心逻辑说明

  1. 任务包装器WrappedTask:

    • 统一捕获任务中的异常,区分取消异常和业务异常
    • 一旦捕获到业务异常,立即调用cts.Cancel()触发全局取消,确保其他任务能收到终止信号
    • 重新抛出异常,让上层catch块处理最终的退出逻辑
  2. 任务内部的取消检查:

    • 每个任务的逻辑中需要主动检查取消令牌(比如token.ThrowIfCancellationRequested()),或者在调用支持取消的API时传入令牌(如Task.Delay(1000, token))
    • 这样任务才能在收到取消信号后立即终止,实现“干净取消”
  3. 资源释放:

    • 使用using声明CancellationTokenSource,确保程序退出时自动释放资源

内容的提问来源于stack exchange,提问作者Chris Davies

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 17:40:02