2011-06-24 53 views
14

我完全不解。我確信如果在一個線程中沒有捕獲到異常,.NET就會關閉整個應用程序域。爲什麼在後臺線程中未處理的異常不會導致應用程序域崩潰?

但是我只是嘗試了下面的代碼,它不會失敗...任何人都可以請解釋爲什麼?

(在.NET 4.0和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(); 
} 

回答

9

發生這種情況,因爲BeginInvoke使用ThreadPool內部,當ThreadPool任何unhadled異常將靜默失敗。但是,如果您使用a.EndInvoke,則未處理的異常將拋出EndInvoke方法。

注意:如João Angelo所述,直接使用ThreadPool方法「如ThreadPool.QueueUserWorkItemsUnsafeQueueUserWorkItem」會在2.0及以上版本中拋出異常。

+2

-1:你的回答也表明,調用'ThreadPool.QueueUserWorkItem'和一個引發異常的方法將導致該框架被異常所吞噬,這在版本2.0和之後並不是這樣。 –

+0

@JoãoAngelo:ThreadPool一般不會拋出異常,例如新的C#4.0任務不會拋出異常,而是像tnd.Wait方法一樣拋出EndInvoke方法。 –

+0

你完全正確。我只是很愚蠢! –

0

,因爲在給定的線程異常拋出停留在那裏,除非它被輸送回主線程。

這就是backgroundWorker爲你做的事情,如果你在BackgroundWorker的線程中有異常,它會在主線程上重新生成。

a.BeginInvoke(null, null); 

這使得異步調用,它創建另一個線程在MSDN上執行此

+0

你正在混合一個'後臺線程'和BackgroundWorker類。 –

+0

不是真的,BackgroundWorker創建後臺線程。正常線程和後退線程之間的唯一區別是後退線程不會從關閉時起保留應用程序,而您必須等待普通線程完成其工作。 –

6

Exceptions in Managed Threads

在.NET Framework 2.0版中, 公共語言運行時允許大多數 線程中未處理的異常以 自然進行。在大多數情況下,這個 意味着未處理的異常 導致應用程序終止。

這是從 版本的.NET Framework 1.0和1.1, 這對於很多 未處理的異常提供了一個逆止器顯著的變化 - 例如,在線程池中的線程 未處理 例外。請參閱本主題後面的更改以前的 版本。

作爲臨時措施兼容性, 管理員可以放置一個 兼容性標誌在應用 配置文件的 部分。這會導致公共語言運行時版本1.0和1.1的行爲恢復爲 。

<legacyUnhandledExceptionPolicy enabled="1"/> 
+0

喬恩感謝你的努力,但你沒有閱讀的問題..問題正是爲什麼它沒有失敗。乾杯 –

+6

我明白了這個問題,我告訴你官方的指導是什麼,並給你一些可能的原因(框架版本,配置設置),以及一些進一步的閱讀,以瞭解正在發生什麼:) –

+17

@Bobb:對於那些試圖免費爲你提供幫助的陌生人,你總是如何迴應你的批評?這對你如何解決? –

3
與異步委託

一般來說,如果該委託方法拋出異常的線程終止,異常將再次調用代碼只有,當你調用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); 
} 
+0

@The Anonymous Downvoter,謹慎解釋你爲什麼認爲這不回答OP問題? –

+0

最好我可以解決Bobb將所有問題都評爲+1或-1,並且不明白downvote是什麼 –

+0

與我無關。這不是不好的答案。 –

相關問題