1. 程式人生 > >多線程(7)多線程中的異常處理

多線程(7)多線程中的異常處理

sch img 技術 pro art div alt 使用 archive

  多線程使用過程中,除了線程同步的問題要考慮外,異常處理也是經常要面對的事情。

默認主線程捕獲不到異步線程的異常

如下代碼:

技術分享

技術分享
 1 namespace ConsoleApplication29
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             //異步線程的異常處理
 8             try
 9             {
10                 Task.Factory.StartNew(() => 
11
{ 12 throw new Exception("異步線和發生異常了!"); 13 }); 14 } 15 catch (Exception ex) 16 { 17 //這裏是捕獲不到的 18 Console.WriteLine(ex.ToString()); 19 } 20 21 Console.ReadKey();
22 } 23 } 24 }
View Code

常用的異常處理方法

1,在異步線程內部使用try/catch

如下代碼:

技術分享

技術分享
 1 namespace ConsoleApplication29
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             //異步線程的異常處理
 8             //1,在異步線程內部使用try/catch
 9             Task.Factory.StartNew(() =>
10
{ 11 try 12 { 13 throw new Exception("異步線和發生異常了!"); 14 } 15 catch (Exception ex) 16 { 17 Console.WriteLine(ex.ToString()); 18 } 19 }); 20 21 Console.ReadKey(); 22 } 23 } 24 }
View Code

運行結果:

技術分享

2,調用Task的Wait方法

如下代碼:

技術分享

註意:

除了調用Task的Wait方法後,在主線程可以捕獲異常外,對於有返回值的Task,只要接收了它的返回值就不再需要調用Wait方法了。

技術分享
 1 namespace ConsoleApplication29
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             //異步線程的異常處理
 8             //2,調用Task的Wait方法
 9             try
10             {
11                 var task = Task.Factory.StartNew(() =>
12                 {
13                     throw new Exception("異步線和發生異常了!");
14                 });
15                 task.Wait();
16             }
17             catch (Exception ex)
18             {
19                 Console.WriteLine(ex.ToString());
20             }
21 
22             Console.ReadKey();
23         }
24     }
25 }
View Code

運行結果:

技術分享

3,在Task的ContinueWith方法中讀取Task的Exception屬性

如下代碼:

技術分享

技術分享
 1 namespace ConsoleApplication29
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             //異步線程的異常處理
 8             //3,在Task的ContinueWith方法中讀取Task的Exception屬性
 9             Task.Factory.StartNew(() =>
10             {
11                 throw new Exception("異步線和發生異常了!");
12             }).ContinueWith(t => 
13             {
14                 if (t.IsFaulted)
15                 {
16                     Console.WriteLine(t.Exception.InnerException);
17                 }
18             }, TaskContinuationOptions.OnlyOnFaulted);
19 
20             Console.ReadKey();
21         }
22     }
23 }
View Code

運行結果:

技術分享

4,全局設置TaskScheduler.UnobservedTaskException

如果異步線程裏的異常沒有被處理,也沒有調用Task.Wait方法將異常傳給主線程處理,最嚴重的後果可能會導致整個應用程序奔潰。詳細原因參考:System.Threading.Tasks.Task引起的IIS應用程序池崩潰

所以,為了保證應用程序不會因為異步線程的異常未被處理導致掛掉,推薦的做法是,全局設置TaskScheduler.UnobservedTaskException。

如果是web程序,可以在Global的Application_Start事件中進行設置,如下代碼:

技術分享

技術分享
1 protected override void Application_Start(object sender, EventArgs e)
2 {
3     System.Threading.Tasks.TaskScheduler.UnobservedTaskException += (s, v) =>
4     {
5         v.SetObserved();
6     };
7 }
View Code

多線程(7)多線程中的異常處理