2015-09-30 94 views
0

我在我的主線程中創建一個任務以管理我的線程。我的目的是受益於AggregateException,所以我希望我的任務能夠在任務中啓動的線程發生異常時返回該異常,如下面的代碼塊中所示。使用任務管理線程異常

public void ReportGeneratorFiveThreadTest() 
{ 
    var logger = new Log4NetLogger(typeof(ReportGeneratorThreadTest)); 
    var tasks = new List<Task>(); 

    for (var i = 0; i < 1; i++) 
    { 
     var estimatedReportSize = EstimatedReportSize.Normal; 
     var thread = new ReportGeneratorThread(logger, new ReportGenerator(20), estimatedReportSize); 
     var task = Task.Factory.StartNew(
     () => 
     { 
      thread.Start();      
     }); 
     tasks.Add(task); 
    } 

    try 
    { 
     Task.WaitAll(tasks.ToArray()); 
     Debug.WriteLine("Tasks are completed"); 
    } 
    catch (AggregateException e) 
    { 
     foreach (var v in e.InnerExceptions) 
     { 
      Debug.WriteLine(e.Message + " " + v.Message); 
     } 
    } 
} 

GenerateReport()方法由啓動的線程調用,它引發此方法中定義的異常。

public void GenerateReport() 
{ 
    var didwork = false; 
    try 
    { 
     didwork = this.reportGenerator.GenerateReport(this.estimatedReportSize); 
    } 
    catch (Exception e) 
    { 
     this.log.LogError(ReportGenerator.CorrelationIdForPickingReport, string.Format(CultureInfo.InvariantCulture, "System"), string.Format(CultureInfo.InvariantCulture, "Error during report generation."), 0, e); 
    } 
    finally 
    { 
     if (!didwork) 
     { 
      Thread.Sleep(Settings.Default.ReportGenerationInterval); 
     } 
    } 
} 

問題是,該異常沒有出現在任務中,因此,在這種情況下不會發生aggregateexception。是否有可能在任務中的線程中出現這種內部錯誤,因此會觸發aggregateexception?。

UPDATE ----------------------

我已經修改我的代碼如下:

public void Start() 
{ 
     this.running = true; 
     this.t = Task.Run(
     () => 
     { 
      this.GenerateReport(); 
     }); 
     try 
     { 
      Task.WaitAny(this.t); 
     } 
     catch (AggregateException e) 
     { 
      foreach (var v in e.InnerExceptions) 
      { 
       Debug.WriteLine(e.Message + " " + v.Message); 
      } 
     } 
} 

,並與:

public void GenerateReport() 
    { 
     var didwork = false;    
     try 
     { 
      didwork = this.reportGenerator.GenerateReport(this.estimatedReportSize);     
     } 
     catch (Exception e) 
     { 
      this.log.LogError(ReportGenerator.CorrelationIdForPickingReport, string.Format(CultureInfo.InvariantCulture, "System"), string.Format(CultureInfo.InvariantCulture, "Error during report generation."), 0, e); 
      throw new InvalidOperationException("Failed"); 
     } 
     finally 
     { 
      if (!didwork) 
      { 
       Thread.Sleep(Settings.Default.ReportGenerationInterval); 
       throw new InvalidOperationException("Failed"); 
      } 
     } 
    } 

,它仍然沒有趕上AggregateException即使出現InvalidOperationException在GenerateReport拋出()方法。

+0

在抓住並記錄後拋出異常。即GenerateReport需要實際拋出。或者,GenerateReport實際上可能會返回一些內容(即null或異常),並且您可以執行任務並遍歷返回值。 – tolanj

+0

這也沒有幫助。看起來主線程在線程拋出異常之前完成了Tasks.WaitAll方法 –

+0

有一些我們在你的'外部'創建任務和GenerateReport方法之間看不到的代碼,我猜你是在捕捉別的地方,如果不要發佈完整的代碼鏈。 – tolanj

回答

0

首先必須在GenerateReport方法

public void GenerateReport() 
{ 
    var didwork = false; 
    try 
    { 
     ... 
    } 
    catch (Exception e) 
    { 
     this.log.LogError(...); 
     throw; // Important! 
    } 
    finally 
    { 
     if (!didwork) 
     { 
      ... 
     } 
    } 
} 

其次,你不應該使用線程中完成任務的catch塊重新拋出異常。僅限使用任務

public void ReportGeneratorFiveThreadTest() 
{ 
    var tasks = new List<Task>(); 

    for (var i = 0; i < 1; i++) 
    { 
     var task = Task.Factory.StartNew(() => 
     { 
      // No need thread here 
      GenerateReport(); 
     }); 
     tasks.Add(task); 
    } 

    try 
    { 
     ... 
    } 
    catch (AggregateException e) 
    { 
     ... 
    } 
} 
+0

請檢查更新 –