如何通过ID取消特定任务

时间:2019-05-14 09:47:06

标签: c# multithreading task cancellationtokensource

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

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

我在这里持有任务ID,因此我知道应该取消哪个任务?

所以请您建议我如何才能通过ID取消单个任务?

在讨论问题之后,我对代码进行了一些更改,因此请建议我应该更改逻辑吗?因为最近我知道任务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取消Task时,在例外情况下,我需要根据该CTS令牌输入符号名称。

2 个答案:

答案 0 :(得分:0)

您可以执行以下操作:

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();
    }
}

答案 1 :(得分:0)

每个取消令牌源是一个单独的逻辑“取消”。如您所见,如果您共享取消令牌,那么一个“取消”将取消所有令牌。

要创建多个逻辑“取消”,您将需要多个取消令牌来源:

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;
  

您能建议我怎样才能仅通过ID取消单个任务吗?

这不可能。

对于一个,不可能从“外部”取消任务。您所能做的就是给它一个令牌并取消该令牌。适当地响应该令牌取决于任务。 cooperative cancellation就是这样的。

还有另一个原因无法实现:task ids are not unique。看来您在代码中使用任务ID;我建议您重新评估设计,以确保它可以处理非唯一任务ID。也许改用实际的Task实例(这是唯一的)。