首页 > 解决方案 > C# .NET CORE:如果返回某种结果,则取消其他任务

问题描述

如果其中一项返回错误(布尔)结果,如何取消所有任务?是否可以确定哪个任务返回了结果?

class Program
    {
        private static Random _rnd = new Random();
        static void Main(string[] args)
        {
            var tasksCounter = _rnd.Next(4, 7);
            var cts = new CancellationTokenSource();

            var tasks = new Task<bool>[tasksCounter];
            for (int i = 0; i < tasks.Length; i++)
            {
                tasks[i] = CreateTask(cts); 
            }

            Console.WriteLine("Waiting..");
            Task.WaitAny(tasks);
            Console.WriteLine("Done!");

            Console.ReadKey();
        }

        private static Task<bool> CreateTask(CancellationTokenSource cts)
        {
            return Task.Factory.StartNew(TaskAction, cts.Token).Unwrap();
        }

        private static async Task<bool> TaskAction()
        {
            var delay = _rnd.Next(2, 5);
            await Task.Delay(delay * 1000);
            var taskResult = _rnd.Next(10) < 4;
            return await Task.FromResult(taskResult);
        }
    }

我尝试使用 Task.WaitAll、Task.WaitAny 等,但这些方法都没有提供有用的(在我的情况下)功能。

标签: c#multitasking.net-core-2.2

解决方案


编辑:
正如@ckuri 在评论中所说,利用现有属性Task而不是编写自定义结果类会更容易。相应地调整了我的答案。

一种解决方案是检查CreateTask()方法中的结果并将 a 传递给CancellationToken您的TaskAction()方法:

private static Task<bool> CreateTask(CancellationTokenSource cts)
{
    return Task.Run(async () =>
    {
        var result = await TaskAction(cts.Token);

        // If result is false, cancel all tasks
        if (!result)
            cts.Cancel();

        return result;
    });
}

private static async Task<bool> TaskAction(CancellationToken token)
{
    // Check for cancellation
    token.ThrowIfCancellationRequested();

    var delay = Rnd.Next(2, 5);
    // Pass the cancellation token to Task.Delay()
    await Task.Delay(delay * 1000, token);

    var taskResult = Rnd.Next(10) < 4;

    // Check for cancellation
    token.ThrowIfCancellationRequested();

    return taskResult;
}

现在你可以在你的方法中做这样的事情Main来接收所有没有被取消的任务:

try
{
    // Wait for all tasks inside a try catch block because `WhenAll` throws a `AggregationException` 
    // containing a `TaskCanceledException`, if the token gets canceled
    await Task.WhenAll(tasks);
} 
catch { }

var tasksWithResult = tasks.Where(t => !t.IsCanceled).ToList();

推荐阅读