如何通过 ID 取消特定任务

How to cancel a specific task by its ID

我有一个 WPF 应用程序,我在其中生成多个任务以进行并行处理。现在,当我的条件变为真时,我需要取消特定的任务。当我为取消任务应用 CancellationTokenSource 时,它​​会取消整个任务,但我只需要取消一个。

Task t1 = Task.Run(() => Task.Delay(30000, token), token);
                test.Add(t1.Id, symbolName);
                lstTask.Add(t1);
                await t1;

这里我持有任务 ID,所以我可以知道我应该取消哪个任务?

所以请你建议我如何才能通过它的 Id 取消单个任务?

在讨论问题后我对代码做了一些修改所以请建议我应该改变我的逻辑吗?因为最近发现task Id不是唯一的所以直接选择CTS

public static async void startAddToPosition(System.Threading.CancellationTokenSource cts1, string symbolName)
{
          try
          {
               Task t1 = Task.Run(() => Task.Delay(30000, cts1.Token), cts1.Token);
                test.Add(symbolName, cts1);
                lstTask.Add(t1);
                lstCts.Add(cts1);
                await t1;
                generateRealPosition("QQQ"); //here I need symbol name when task will complete it's 30 seconds.
          }
          catch (OperationCanceledException ex)
          {
                var symbolName = test.FirstOrDefault(q => q.Value.Token == ex.CancellationToken).Key;
            }
}

然而另一方面,当条件变为满时,我正在尝试取消如下任务:

CancellationTokenSource cts = Evaluation.parallelScripts.test.FirstOrDefault(q => q.Key == eventData.symbolName).Value;
  cts.Cancel();

所以我试图从列表中获取特定符号的 CancellationTokenSource 并取消该 CTS。这样任务就取消了。

所以我的问题是我不知道 CTS 令牌是否唯一。因为当 CTS 取消任务时,在异常情况下我需要根据该 CTS 令牌的符号名称。

你可以这样做:

class Program
{
    static void Main(string[] args)
    {
        Guid lastID = default(Guid);
        List<CancellableTask> cancellableTasks = new List<CancellableTask>();
        for (int i = 0; i < 10; i++)
        {
            CancellableTask task = new CancellableTask(() =>
            {
                Console.WriteLine("New task!");
                Thread.Sleep(3000);
            });
            cancellableTasks.Add(task);
            lastID = task.ID;
        }

        CancellableTask cancellableTask = cancellableTasks.FirstOrDefault(x => x.ID == lastID);
        if (cancellableTask != null)
        {
            cancellableTask.Cancel();
        }
    }
}

public class CancellableTask
{
    public Guid ID { get; private set; }
    private CancellationTokenSource CancellationTokenSource { get; set; }
    public Task Task { get; private set; }
    public CancellableTask(Action action)
    {
        CancellationTokenSource = new CancellationTokenSource();
        Task = Task.Run(action, CancellationTokenSource.Token);
        ID = Guid.NewGuid();
    }
    public void Cancel()
    {
        CancellationTokenSource.Cancel();
    }
}

每个取消令牌源都是一个单独的逻辑 "cancel"。正如您所发现的,如果您共享取消令牌,那么单个 "cancel" 将取消所有这些令牌。

要创建多个逻辑 "cancel",您需要多个取消令牌来源:

CancellationTokenSource cts1 = new CancellationTokenSource();
Task t1 = Task.Run(() => Task.Delay(30000, cts1.Token), cts1.Token);
test.Add(t1.Id, symbolName, cts1);
lstTask.Add(t1);
lstCts.Add(cts1);
await t1;

can you suggest me that how can I able to cancel only single Task by it's Id ?

这是不可能的。

一方面,无法从 "outside" 取消任务。您所能做的就是给它一个令牌并取消该令牌。适当地响应该令牌取决于任务。这就是 cooperative cancellation 的工作原理。

这是不可能的另一个原因:task ids are not unique。看来您在代码中使用了任务 ID;我向您推荐 re-evaluate 设计以确保它可以处理 non-unique 任务 ID。也许改用实际的 Task 实例(这是唯一的)。