Task.WaitAll and Exceptions

后端 未结 3 1301
粉色の甜心
粉色の甜心 2020-12-23 21:30

I have a problem with exception handling and parallel tasks.

The code shown below starts 2 tasks and waits for them to finish. My problem is, that in case a task thr

相关标签:
3条回答
  • 2020-12-23 21:49

    I was trying to create a call for each item in a collection, which turned out something like this:

    var parent = Task.Factory.StartNew(() => {
      foreach (var acct in AccountList)
        {
          var currAcctNo = acct.Number;
          Task.Factory.StartNew(() =>
          {
            MyLocalList.AddRange(ProcessThisAccount(currAcctNo));
          }, TaskCreationOptions.AttachedToParent);
          Thread.Sleep(50);
        }
      });
    

    I had to add the Thread.Sleep after each addition of a child task because if I didn't, the process would tend to overwrite the currAcctNo with the next iteration. I would have 3 or 4 distinct account numbers in my list, and when it processed each, the ProcessThisAccount call would show the last account number for all calls. Once I put the Sleep in, the process works great.

    0 讨论(0)
  • 2020-12-23 21:59

    Can't reproduce this - it works fine for me:

    using System;
    using System.Threading;
    using System.Threading.Tasks;
    
    class Test
    {
        static void Main()
        {
            Task t1 = Task.Factory.StartNew(() => Thread.Sleep(1000));
            Task t2 = Task.Factory.StartNew(() => {
                Thread.Sleep(500);
                throw new Exception("Oops");
            });
    
            try
            {
                Task.WaitAll(t1, t2);
                Console.WriteLine("All done");
            }
            catch (AggregateException)
            {
                Console.WriteLine("Something went wrong");
            }
        }
    }
    

    That prints "Something went wrong" just as I'd expect.

    Is it possible that one of your tasks isn't finished? WaitAll really does wait for all the tasks to complete, even if some have already failed.

    0 讨论(0)
  • 2020-12-23 22:04

    Here's how I solved the problem, as alluded to in the comments on my answer/question (above):

    The caller catches any exceptions raised by the tasks being coordinated by the barrier, and signals the other tasks with a forced cancellation:

    CancellationTokenSource cancelSignal = new CancellationTokenSource();
    try
    {
        // do work
        List<Task> workerTasks = new List<Task>();
        foreach (Worker w in someArray)
        {
            workerTasks.Add(w.DoAsyncWork(cancelSignal.Token);
        }
        while (!Task.WaitAll(workerTasks.ToArray(), 100, cancelSignal.Token)) ;
    
     }
     catch (Exception)
     {
         cancelSignal.Cancel();
         throw;
     }
    
    0 讨论(0)
提交回复
热议问题