[英]how to crash the main process if there is unhandled exception inside background thread
[英]Why unhandled exception in a background thread doesnt crash the app domain?
我完全不解。 如果在我從未測試過的線程中存在未捕獲的異常,我確信.NET會關閉整個應用程序域。
但是,我只是嘗試了下面的代碼,它沒有失敗......任何人都可以解釋為什么?
(在.NET 4和3.5中嘗試過)
static void Main(string[] args)
{
Console.WriteLine("Main thread {0}", Thread.CurrentThread.ManagedThreadId);
Action a = new Action(() =>
{
Console.WriteLine("Background thread {0}", Thread.CurrentThread.ManagedThreadId);
throw new ApplicationException("test exception");
});
a.BeginInvoke(null, null);
Console.ReadLine();
}
發生這種情況是因為BeginInvoke
內部使用ThreadPool
而當ThreadPool
任何未處理的異常將是靜默失敗。 但是,如果使用a.EndInvoke
,則將在EndInvoke
方法中拋出未處理的異常。
注意:如João Angelo
說,使用ThreadPool
方法直接“像ThreadPool.QueueUserWorkItems
和UnsafeQueueUserWorkItem
”將在2.0及以上拋出異常。
從MSDN上的托管線程中的例外 :
在.NET Framework 2.0版中,公共語言運行庫允許線程中大多數未處理的異常自然地進行。 在大多數情況下,這意味着未處理的異常會導致應用程序終止。
這是.NET Framework版本1.0和1.1的重大變化,它為許多未處理的異常提供了支持 - 例如,線程池線程中的未處理異常。 請參閱本主題后面的“從先前版本更改”。
作為臨時兼容性措施,管理員可以在應用程序配置文件的部分中放置兼容性標志。 這會導致公共語言運行庫恢復到版本1.0和1.1的行為。
<legacyUnhandledExceptionPolicy enabled="1"/>
通常使用異步委托,如果委托方法拋出異常,則線程終止,並且只有在調用EndInvoke
時才會在調用代碼中再次拋出異常。
這就是使用異步委托( BeginInvoke
)時應始終調用EndInvoke
。 此外,這不應與Control.BeginInvoke
混淆,后者可以以一種火災和忘記方式調用。
我之前通常說過,因為如果委托方法返回void,你有可能聲明應該忽略該異常。 為此,您需要使用OneWay
屬性標記方法。
如果運行以下示例,則在調用willNotIgnoreThrow.EndInvoke
時只會出現異常。
static void Throws()
{
Console.WriteLine("Thread: {0}", Thread.CurrentThread.ManagedThreadId);
throw new ApplicationException("Test 1");
}
[OneWay]
static void ThrowsButIsIgnored()
{
Console.WriteLine("Thread: {0}", Thread.CurrentThread.ManagedThreadId);
throw new ApplicationException("Test 2");
}
static void Main(string[] args)
{
Console.WriteLine("Main: {0}", Thread.CurrentThread.ManagedThreadId);
var willIgnoreThrow = new Action(ThrowsButIsIgnored);
var result1 = willIgnoreThrow.BeginInvoke(null, null);
Console.ReadLine();
willIgnoreThrow.EndInvoke(result1);
Console.WriteLine("============================");
var willNotIgnoreThrow = new Action(Throws);
var result2 = willNotIgnoreThrow.BeginInvoke(null, null);
Console.ReadLine();
willNotIgnoreThrow.EndInvoke(result2);
}
因為對給定線程的異常拋出會保留在那里,除非它被引導回主線程。
這就是backgroundWorker為你做的,如果你在BackgroundWorker的線程中有異常,它會在主線程上重新拋出。
a.BeginInvoke(null, null);
這會產生異步調用,這會創建另一個執行此操作的線程
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.