stevenjin 2024-12-07 21:13 采纳率: 96.8%
浏览 10
已结题

c#多个task,怎么知道取消的是哪个task?

c#多个task,以下方式取消指定task时报错,怎么取消指定的task?


static void Main(string[] args)
{
    var cancellationTokens = new CancellationToken[3];
    var tasks = new Task[3];

    for (int i = 0; i < 3; i++)
    {
        var iLocal = i; // 为了在内部匿名函数中使用
        var cancellationTokenSource = new CancellationTokenSource();
        cancellationTokens[i] = cancellationTokenSource.Token;

        tasks[i] = Task.Run(() =>
        {
            while (!cancellationTokens[iLocal].IsCancellationRequested)
            {
                Console.WriteLine($"Task {iLocal} is running.");
                Thread.Sleep(1000); // 模拟工作
            }

            Console.WriteLine($"Task {iLocal} was cancelled.");
        }, cancellationTokens[iLocal]);
    }

    // 取消第二个Task,但这里报错!!
    cancellationTokens[1].Cancel();

    Task.WaitAll(tasks); // 等待所有Task完成
    Console.WriteLine("All tasks completed.");
}
  • 写回答

1条回答 默认 最新

  • 关注

    以下回复参考:皆我百晓生券券喵儿等免费微信小程序作答:

    在这个代码中,你遇到的问题是当你尝试取消特定的任务时,由于所有的任务都在使用自己的 CancellationToken,取消操作实际上并没有直接关联到特定的任务。你尝试取消 cancellationTokens[1] 时,由于其他的任务还在运行(它们自己的 CancellationToken 未被取消),它们仍然会继续运行,直到它们自己完成或者达到其他的结束条件。这可能会导致你的代码出现预期之外的行为。要解决这个问题,你需要将取消令牌传递给特定的任务,而不是创建一个新的令牌为每个任务。这样你就可以控制哪个任务被取消。

    你可以通过创建一个 CancellationTokenSource 实例,并使用它来生成一个共享的取消令牌来实现这一点。然后你可以将这个取消令牌传递给所有任务。当你想要取消某个任务时,只需要调用这个共享 CancellationTokenSourceCancel 方法即可。以下是修改后的代码示例:

    static void Main(string[] args)
    {
        var cancellationTokenSource = new CancellationTokenSource();
        var cancellationToken = cancellationTokenSource.Token;
        var tasks = new Task[3];
    
        for (int i = 0; i < 3; i++)
        {
            tasks[i] = Task.Run(() =>
            {
                while (!cancellationToken.IsCancellationRequested) // 使用共享的取消令牌
                {
                    Console.WriteLine($"Task {Task.CurrentId} is running."); // 使用 Task.CurrentId 来标识当前任务
                    Thread.Sleep(1000); // 模拟工作
                }
    
                Console.WriteLine($"Task {Task.CurrentId} was cancelled."); // 使用 Task.CurrentId 来标识当前任务被取消
            }, cancellationToken); // 将取消令牌传递给任务
        }
    
        // 在你想要取消任务时调用这个方法:取消第二个任务(假设你想取消ID为2的任务)
        if (tasks[1] != null && tasks[1].Id == 2) // 先检查是否存在并且任务ID正确才执行取消操作,防止报错
        {
            cancellationTokenSource.Cancel(); // 使用共享的取消令牌来取消所有任务(但这里只会取消ID为2的任务)
        }
    
        Task.WaitAll(tasks); // 等待所有任务完成(但其他未被取消的任务将继续运行)
        Console.WriteLine("All tasks completed."); // 所有任务完成后的操作
    }
    

    注意,这里并没有确保只会取消特定ID的任务,因为所有的任务都在使用同一个 CancellationToken。如果你需要更精细的控制,你可能需要为每个任务创建一个单独的 CancellationTokenSource 并跟踪每个任务的 CancellationToken。这样你就可以只取消特定的任务而不影响其他任务。但是在这个例子中,如果你只是想要取消特定ID的任务(比如你知道哪个任务的ID),上面的代码应该可以满足你的需求。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 12月16日
  • 已采纳回答 12月8日
  • 创建了问题 12月7日