当其中一个子任务抛出异常时取消子任务

本文关键字:子任务 一个 抛出异常 取消 | 更新日期: 2023-09-27 17:54:25

我想改进以下代码以添加取消支持。基本上,我需要做的是一旦子任务抛出异常,就取消所有子任务以及父任务。我写了下面的代码作为学习经验。我只能在所有孩子完成后才能看到AggregateException,但我不希望那样。

    static int GetSum()
    {
        var parent = Task<int>.Factory.StartNew(() =>
        {
            var children = new Task<int>[100];
            for (var i = 0; i < children.Length; i++)
            {
                var index = i;
                children[index] = Task<int>.Factory.StartNew(() =>
                {
                    var randomNumber = new Random().Next(5);
                    if (randomNumber == 0)
                    {
                        throw new Exception();
                    }
                    return randomNumber;
                }, TaskCreationOptions.AttachedToParent);
            }
            Task.WaitAll();
            Console.WriteLine("Children finished");
            return children.Sum(t => t.Result);
        });
        parent.Wait();
        Console.WriteLine("Parent finished");
        return parent.Result;
    }

我认为我需要使用下面的代码,尽管我不知道如何使用:

var source = new CancellationTokenSource();
var token = source.Token;

当其中一个子任务抛出异常时取消子任务

您可以使用 Task.WaitAny 代替WaitAll,并在抛出aggreateexception时向令牌发出取消请求像这样

static int GetSum()
    {
        var tokenSource = new CancellationTokenSource();
        var token = tokenSource.Token;
        var parent = Task<int>.Factory.StartNew(() =>
        {
            var children = new Task<int>[100];
            for (var i = 0; i < children.Length; i++)
            {
                var index = i;
                children[index] = Task<int>.Factory.StartNew(() =>
                {
                    for (int j = 0; j < 100000; j++)
                    {

                    if (!token.IsCancellationRequested)
                    {

                        var randomNumber = new Random().Next(5);
                        if (randomNumber == 0)
                        {
                            throw new Exception();
                        }
                        return randomNumber;
                    }
                    else
                    {
                        token.ThrowIfCancellationRequested();
                    }
                    }
                    return 0;
                }
                , token);
            }
            try
            {
                Task.WaitAny(children);
            }
            catch (AggregateException ae)
            {
                tokenSource.Cancel();
                ae.Handle((task) =>
                    {
                        Console.WriteLine("Cancel all others child tasks  requested ");
                        return true;
                    });
            }
            Console.WriteLine("Children finished");
            return children.Sum(t => t.Result);
        });
        try
        {
            parent.Wait();
        }
        catch (AggregateException aex)
        {
            aex.Handle((task) =>
            {
                Console.WriteLine("Cancel child work  done ");
                return true;
            });              
        }
        Console.WriteLine("Parent finished");
        return parent.Result;
    }