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

时间:2014-03-28 15:02:26

标签: c# multitasking

我想改进以下代码以添加取消支持。基本上,我需要做的是在孩子抛出异常时取消所有孩子以及父任务。我将以下代码作为学习经历编写。我可以在所有孩子完成后看到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;

1 个答案:

答案 0 :(得分:2)

你可以使用Task.WaitAny而不是WaitAll,并在抛出类似这样的AgregateException时对令牌发出取消请求

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