2014-04-25 57 views
4

我有一個處理事件回調的應用程序,在我的情況下它是一個SerialPort上的DataReceived事件。在該回調中,我有業務邏輯需要在另一個線程上引發異常。該線程正在等待事件偵聽器發送消息,或讓它知道發生了異常。多線程異常冒泡

什麼是保留在線程的堆棧跟蹤的最佳方式?

一個簡單的傳遞線程切換到工作線程,並重新拋出它,會導致丟失堆棧跟蹤。

+0

它真的需要成爲例外嗎?您可以用其他方式報告狀態,這可能會更容易,更有效率。 –

+0

這是一個非常模糊的問題。有很多種方法可以做到這一點。 – Botonomous

+0

我會在工作線程中捕獲異常,並將異常對象傳遞給主線程,您可以根據需要處理它。 – Polyfun

回答

2
  • 這取決於你的方法,例如TPL:throw - > AggregateException。
  • BackGroundWorker - >您必須注意結果中的錯誤。
  • 線程 - >你必須將錯誤編入主線程。
  • 任務 - > throw - > AggregateException。
  • Async/await - > throw也AggregateException(我不確定)。

任務方法提供了一個處理由先行和良好錯誤處理引發的異常的延續。

異步/等待非常靈活。

BackGroundWroker是遺留的,但仍然有時需要。

帶回調的異步編程(在你的情況下也是遺留的),但它可以使用;我建議你使用任務。

AggregateException:表示應用程序執行期間發生的一個或多個錯誤。你會得到一個列表的異常(從其他線程)在AggregateException

0

這裏有兩個建議:

首先,我會考慮處理在事件處理程序的異常(串行端口的線程),和信令主線程做什麼是你想做的事情。

如果你真的要處理的主線程之外,你也可以調用你想(如果你喜歡,甚至是整個事件處理)做在主線程的工作。這樣,首先會在主線程上拋出異常。如果有繁重的工作要做,你可以把它卸載到一項任務中(and handle exceptions like this)。這也具有不阻塞串行端口線程的優點,並且可能由於用盡緩衝空間而丟失數據。

0

我相信你的問題是隻爲回答您的問題,
正如你所說That thread is waiting for the event listener to send it a message, or let it know an exception has occurred.

因爲你已經有一個事件監聽器到線程等待,以同樣的方式,你可以發送Exception代替消息並獲取觸發的線程以採取適當的措施。

0

一到「大多是」保留的堆棧跟蹤的方式是在傳遞異常給其他線程,然後使用相同類型的重建是例外,但通過原始異常作爲的InnerException:

// retain the exception type, but don't lose the stack trace. 
Exception instance = (Exception)Activator.CreateInstance(ex.GetType(), "", ex); 
throw instance; 

這並不完美,但至少堆棧跟蹤不會丟失。

0

我從來沒有嘗試過這一點,但有一個新的類在.Net4.5 ExceptionDispatchInfo它可以用來保存堆棧跟蹤一個例外。看看this

2

如果您在.NET 4.5,那麼你可以使用ExceptionDispatchInfo這樣:

Exception exception = ...; 
ExceptionDispatchInfo.Capture(exception).Throw(); 

如果你在.NET 4.0,那麼你必須使用一個更hackish的解決方案:

Exception exception = ...; 
typeof(Exception).InvokeMember("PrepForRemoting", 
    BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod, 
    null, exception, new object[0]); 
throw exception; 
0

如果線程是同一類的一部分,只需添加它做一個列表,並把它當其他方法被調用:

public class MyProcessor 
{ 
    List<Exception> _threadExceptions = new List<Exception>(); 

    public void Enqueue(SomeJob job) 
    { 
     if (_threadExceptions.Count > 0) 
     { 
      var myList = _threadExceptions; 
      _threadExceptions = new List<Exception>(); 
      throw new AggregateException(myList); 
     } 

     //do some work 
    } 

    private static void YourThreadFunc() 
    { 
     try 
     { 
      //listen to the port 
     } 
     catch (Exception ex) 
     { 
      _threadExceptions.Add(ex); 
     } 
    } 
} 

由於線程和Enqueue方法之間沒有確切的時間邊界,因此我們可以替換異常列表,就像沒有任何處罰(並且可以避免使用線程同步)。