WaitAll(Task [],TimeSpan)不会抛出任务异常

时间:2019-07-25 17:23:47

标签: c#

我创建了一个任务数组,并使用WaitAll触发了TimeSpan

如果任务花费的时间超过了超时,则不会重新抛出其他线程抛出的Exception

就像下面的示例代码一样,第一个线程休眠7秒,其他线程休眠5秒,然后抛出Exception。我希望catch重新抛出Exception

public static void Main(string[] args)  
{  
    List<Task> tasks = new List<Task>();

    tasks.Add(Task.Factory.StartNew(() =>
    {
        Console.WriteLine("This one will sleep");
        Thread.Sleep(2000);
        Console.WriteLine("Snoozed for 20 seconds");
        Thread.Sleep(5000);
    }));

    tasks.Add(Task.Factory.StartNew(() =>
        {
            Console.WriteLine("Starting afresh");
            Thread.Sleep(5000);
            throw new Exception("Can't wait any longer");
        }));
    try
    {
       Task.WaitAll(tasks.ToArray(), new TimeSpan(0, 0, 6));
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
         throw;
    }  
}

但是,如果两个线程都在TimeSpan中完成,则抛出错误

我想了解WaitAll异常的工作原理

编辑

有关我的要求的更多信息:

我有2个任务-一个任务启动一个I / O

tasks.Add(Task.Factory.StartNew(() =>
{
    WriteFile(filePath, fileSize);
}));

其他人重新启动启动了I / O的计算机,验证计算机在45分钟内重新启动,否则引发异常

 tasks.Add(Task.Factory.StartNew(() =>
 {                
     InducePanic();
     WaitForReboot(new TimeSpan(0, 45, 0));   # This method throws Exception if >45 minutes
     ....

WaitAll就是这样

 try
 {
     Task.WaitAll(tasks.ToArray(), new TimeSpan(0, 60, 0));
 }
 catch (Exception ex)
 {
     if (!ex.Message.Contains("System.IO.IOException"))
         throw;

问题在于任务2 throws Exception不能在45分钟内完成重启。但是任务1仍在进行中

60分钟后,代码继续执行,Exception丢失了

2 个答案:

答案 0 :(得分:0)

WaitAll将在活动时将异常带出您的任务,但是当达到超时时,它将结束。它不会继续监听您的任务,以查看它们是否会在此之后引发异常。

如果要继续监视它们的异常情况,可以自己在有问题的任务后附加.ContinueWith,并检查先前的任务是否出错以获取异常。

答案 1 :(得分:0)

这就是我要解决的方法。我不喜欢,但是无论如何

try
  {
    bool tasks_finished = false;

    tasks_finished = Task.WaitAll(tasks.ToArray(), new TimeSpan(0, 60, 0));

    if (!tasks_finished)
      foreach (var ongoing_task in tasks.ToArray())
        {
          if (ongoing_task.IsFaulted)
            throw ongoing_task.Exception;
        }
  }
catch (Exception ex)
  {
    ...
    throw;
  }

注意

仅当其中一个线程具有faulted时,此解决方案才有效。如果两者仍在进行,则解决方案将失败