stevenjin 2024-12-08 19:44 采纳率: 96.8%
浏览 34
已结题

c#多个task,cancellationToken时怎样取消指定的task?

以下多任务时,使用了多个task,当取消指定Id的task时,后面的全部被取消了。怎样只取消指定的task呢?


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

                 Console.WriteLine($"Task {Task.CurrentId} was cancelled."); // 使用 Task.CurrentId 来标识当前任务被取消
             }, cancellationToken); // 将取消令牌传递给任务
         }

         

         Task.WaitAll(tasks); // 等待所有任务完成(但其他未被取消的任务将继续运行)
         Console.WriteLine("All tasks completed."); // 所有任务完成后的操作
     }
     catch (Exception)
     {

         throw;
     }
    
     Console.ReadKey();
 }
  • 写回答

1条回答 默认 最新

  • 关注

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

    在 C# 中,如果你想要取消特定的任务,你不能直接取消指定的 Task 实例。CancellationTokenSourceCancel 方法会触发所有使用同一 CancellationToken 的任务进行取消操作。因此,如果你想要单独控制每个任务是否取消,你需要为每个任务创建一个单独的 CancellationTokenSource 实例。这样,你可以独立地取消特定的任务。

    以下是修改后的代码示例,为每个任务创建单独的取消令牌源,并只取消特定的任务:

    static void Main(string[] args)
    {
        var tasks = new Task[3];
        try
        {
            for (int i = 0; i < 3; i++)
            {
                // 为每个任务创建单独的 CancellationTokenSource 实例
                var cancellationTokenSource = new CancellationTokenSource();
                var cancellationToken = cancellationTokenSource.Token;
                tasks[i] = Task.Run(() =>
                {
                    // 模拟工作,检查特定任务的取消令牌是否已取消请求(假设你想要取消ID为特定值的任务)
                    while (true) // 循环直到收到取消请求为止(模拟长时间运行的任务)
                    {
                        if (i == 1 && /* 需要取消的条件 */) // 检查是否需要取消当前任务(假设ID为特定值)并作出相应的操作
                        {
                            cancellationTokenSource.Cancel(); // 仅取消当前任务关联的取消令牌源对应的任务
                            break; // 任务一旦接收到取消信号,则跳出循环并退出任务
                        }
                        Thread.Sleep(1000); // 模拟工作负载,这里只是一个示例,实际情况下可能会有其他操作或逻辑判断等。
                    } // 注意这里没有使用 CancellationToken 的 IsCancellationRequested 属性来检查是否应该退出循环,因为每个任务都有自己的 CancellationTokenSource 实例。退出循环的逻辑由你的业务逻辑决定。当你认为任务应该退出时(比如接收到特定的取消信号),你应该退出循环。因此这个循环需要设计为可以安全退出的循环结构。否则,如果任务永远不退出循环,即使取消了 CancellationTokenSource 也无法终止任务。因此,你需要确保在适当的时候退出循环。一旦退出循环,由于 Task 是基于线程的,线程将结束执行并结束任务。当所有任务都完成时,它们会自动从内存中清理掉。一旦任务开始运行,直到你明确终止它之前,它都会持续运行下去。这包括检查是否应该继续运行或者是否已经接收到取消信号等逻辑。这需要在你的业务逻辑中设计好。否则你可能会遇到无限循环等问题。另外请注意不要在任务内部保留未处理或永远不会被完成的任务的资源以防止资源泄漏或应用无法结束的问题发生。通常情况下确保在完成你的业务逻辑工作后或者你的程序要退出时清理掉所有相关的资源是非常重要的。在你的例子中每个任务都有自己的 CancellationTokenSource 实例所以你可以独立地控制每个任务的执行和取消操作。如果你想要确保某个任务被正确地取消了你可以使用 Task 的 Wait 方法等待该任务的完成或者检查它的状态以确定它是否已经被取消或者已经完成了它的工作等。这样你就可以确保你正在控制正确的任务的执行状态而不会误取消其他任务的执行操作。使用 Task 来执行异步操作时通常会通过异常捕获来避免程序的异常崩溃或避免程序的异常行为的发生从而保证程序的健壮性是非常重要的。", "Task {Task.CurrentId} is running."); // 使用 Task.CurrentId 来标识当前任务Console.WriteLine($"Task {Task.CurrentId} was cancelled."); // 如果取消令牌触发并且当前任务检测到取消请求时输出此信息Console.WriteLine($"Task {Task.CurrentId} completed."); // 输出完成的信息");", cancellationToken); // 使用正确的取消令牌对每个任务进行操作                            Console.WriteLine($"Task {tasks[i].Id} was started."); // 开始记录任务的ID} catch (Exception ex) { // 处理可能的异常情况 Console.WriteLine($"An error occurred: {ex.Message}"); } Console.ReadKey(); } }```在这个修改后的代码中,我们为每个任务创建了一个单独的 `CancellationTokenSource` 实例并将其传递给相应的 `Task` 实例中的方法。当需要取消特定的任务时,我们调用该特定任务的 `CancellationTokenSource` 实例的 `Cancel` 方法来触发该任务的取消操作而不是全局的 `CancellationTokenSource` 实例的 `Cancel` 方法。这样我们就可以单独控制每个任务的执行和取消操作了。请注意代码中的注释部分解释了为什么需要这样做以及如何处理异步操作的各个方面来确保代码的健壮性和正确的工作流程的实现等事项以保证代码的可靠运行和使用。在真实的异步操作中通常会遇到更复杂的场景和需要更多的设计和编程经验来保证异步代码的正确实现和安全执行等等。"这是一个常见的实践对于确保正确的控制和调度长时间运行的任务或者其他重要的系统组件至关重要因为正确处理并发操作和控制系统的运行状态能够带来更高效的应用性能并提高用户体验保证程序的可靠性和健壮性减少可能出现的错误和问题等等。"
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

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