我有一個處理事件回調的應用程序,在我的情況下它是一個SerialPort上的DataReceived事件。在該回調中,我有業務邏輯需要在另一個線程上引發異常。該線程正在等待事件偵聽器發送消息,或讓它知道發生了異常。多線程異常冒泡
什麼是保留在線程的堆棧跟蹤的最佳方式?
一個簡單的傳遞線程切換到工作線程,並重新拋出它,會導致丟失堆棧跟蹤。
我有一個處理事件回調的應用程序,在我的情況下它是一個SerialPort上的DataReceived事件。在該回調中,我有業務邏輯需要在另一個線程上引發異常。該線程正在等待事件偵聽器發送消息,或讓它知道發生了異常。多線程異常冒泡
什麼是保留在線程的堆棧跟蹤的最佳方式?
一個簡單的傳遞線程切換到工作線程,並重新拋出它,會導致丟失堆棧跟蹤。
任務方法提供了一個處理由先行和良好錯誤處理引發的異常的延續。
異步/等待非常靈活。
BackGroundWroker是遺留的,但仍然有時需要。
帶回調的異步編程(在你的情況下也是遺留的),但它可以使用;我建議你使用任務。
AggregateException:表示應用程序執行期間發生的一個或多個錯誤。你會得到一個列表的異常(從其他線程)在AggregateException
這裏有兩個建議:
首先,我會考慮處理在事件處理程序的異常(串行端口的線程),和信令主線程做什麼是你想做的事情。
如果你真的要處理的主線程之外,你也可以調用你想(如果你喜歡,甚至是整個事件處理)做在主線程的工作。這樣,首先會在主線程上拋出異常。如果有繁重的工作要做,你可以把它卸載到一項任務中(and handle exceptions like this)。這也具有不阻塞串行端口線程的優點,並且可能由於用盡緩衝空間而丟失數據。
我相信你的問題是隻爲回答您的問題,
正如你所說That thread is waiting for the event listener to send it a message, or let it know an exception has occurred.
因爲你已經有一個事件監聽器到線程等待,以同樣的方式,你可以發送Exception
代替消息並獲取觸發的線程以採取適當的措施。
一到「大多是」保留的堆棧跟蹤的方式是在傳遞異常給其他線程,然後使用相同類型的重建是例外,但通過原始異常作爲的InnerException:
// retain the exception type, but don't lose the stack trace.
Exception instance = (Exception)Activator.CreateInstance(ex.GetType(), "", ex);
throw instance;
這並不完美,但至少堆棧跟蹤不會丟失。
我從來沒有嘗試過這一點,但有一個新的類在.Net4.5 ExceptionDispatchInfo它可以用來保存堆棧跟蹤一個例外。看看this
如果您在.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;
如果線程是同一類的一部分,只需添加它做一個列表,並把它當其他方法被調用:
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方法之間沒有確切的時間邊界,因此我們可以替換異常列表,就像沒有任何處罰(並且可以避免使用線程同步)。
它真的需要成爲例外嗎?您可以用其他方式報告狀態,這可能會更容易,更有效率。 –
這是一個非常模糊的問題。有很多種方法可以做到這一點。 – Botonomous
我會在工作線程中捕獲異常,並將異常對象傳遞給主線程,您可以根據需要處理它。 – Polyfun