2010-05-13 61 views
7

我正在閱讀一本關於通用c#開發的書,我已經到了線程中止部分。捕捉ThreadAbortException時隱藏Throw的處理是什麼?

這本書說了一些事情,當你在另一個線程上調用Thread.Abort()時,該線程將拋出一個ThreadAbortException異常,即使你試圖禁止它,它也會自動重新拋出它,除非你做了一些bs這通常是皺眉。這裏提供了一個簡單的例子。

using System; 
using System.Threading; 

public class EntryPoint 
{ 
    private static void ThreadFunc() 
    { 
     ulong counter = 0; 
     while (true) 
     { 
      try 
      { 
       Console.WriteLine("{0}", counter++); 
      } 
      catch (ThreadAbortException) 
      { 
       // Attempt to swallow the exception and continue. 
       Console.WriteLine("Abort!"); 
      } 
     } 
    } 

    static void Main() 
    { 
     try 
     { 
      Thread newThread = new Thread(new ThreadStart(EntryPoint.ThreadFunc)); 
      newThread.Start(); 
      Thread.Sleep(2000); 

      // Abort the thread. 
      newThread.Abort(); 

      // Wait for thread to finish. 
      newThread.Join(); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.ToString()); 
     } 
    } 
} 

書中說:

當你的線程處理完終止異常,運行時隱式重新拋出它在異常處理程序的結束。就像你自己重新拋出異常一樣。因此,任何外部異常處理程序或finally塊仍將正常執行。在這個例子中,加入的呼叫不會像最初預期的那樣永遠等待。

因此,我圍繞Thread.Abort()調用包裝了一個try catch,並設置了一個斷點,期待它打到這個位置,考慮到文本顯示「任何外部異常處理程序或finally塊仍將正常執行」。但它不是。我正在絞盡腦汁想出原因。

任何人有任何想法,爲什麼不是這種情況?這本書是錯的嗎?

在此先感謝。

+1

你的程序輸出了什麼? – 2010-05-13 21:21:37

+1

我希望這本書也提到Thread.Abort是邪惡的,不應該被使用。 – 2010-05-13 21:38:04

+0

約寫20秒#儘可能多,然後中止!,然後它返回。 – priehl 2010-05-13 21:41:15

回答

8

在被中止的線程上拋出異常。一旦拋出一個異常遍歷該線程的調用棧,但它不會跳轉到另一個線程,也不會跳轉到Thread.Abort的調用者。

根據權利要求是:

因此,任何外部的異常處理程序或最後塊仍然將執行正常。

這種說法的一個更好的檢驗是下面的代碼:

private static void ThreadFunc() 
{ 
    ulong counter = 0; 
    while (true) 
    { 
     try 
     { 
      try 
      { 
       Console.WriteLine("{0}", counter++); 
      } 
      catch (ThreadAbortException) 
      { 
       // Attempt to swallow the exception and continue. 
       Console.WriteLine("Abort!"); 
      } 
     } 
     catch (ThreadAbortException) 
     { 
      Console.WriteLine("Do we get here?"); 
     } 
    } 
} 

如果ThreadAbortException是一個正常的異常類型,我們不希望打線"Do we get here?"的,但是我們做的。

1

Thread.Abort()不拋出異常。而是在線程中拋出一個異常,即使你捕獲它,它也會立即被重新拋出。在你的情況下,它會在打印「Abort!」後重新排列。繼續在另一個try/catch中包裝線程方法的主體,然後您就可以確認這一點。

1

你可能眨了眨眼睛,看不見它。修改你的代碼是這樣的:

 // Wait for thread to finish. 
     newThread.Join(); 
     Console.ReadLine(); 

可能的輸出:

.... 
8807 
8808 
Abort! 
0

當您啓動線程,你的代碼的推移,你開始是單獨運行的線程,即爲什麼我們不應該指望打主線。

using System; 
using System.Threading; 

public class EntryPoint 
{ 
    private static void ThreadFunc() 
    { 
     try 
     { 
      ulong counter = 0; 
      while (true) 
      { 
       try 
       { 
        Console.WriteLine("{0}", counter++); 
       } 
       catch (ThreadAbortException) 
       { 
        // Attempt to swallow the exception and continue. 
        Console.WriteLine("Abort!"); 
       } 
      } 
     } 
     catch(ThreadAbortException) 
     { 
      Console.WriteLine("Certainly unstoppable!"); 
     } 
    } 

    static void Main() 
    { 
     try 
     { 
      Thread newThread = new Thread(new ThreadStart(EntryPoint.ThreadFunc)); 
      newThread.Start(); 
      Thread.Sleep(2000); 

      // Abort the thread. 
      newThread.Abort(); 

      // Wait for thread to finish. 
      newThread.Join(); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.ToString()); 
     } 
    } 
} 

記住ThreadAbortException它的一個v。特殊的例外,因爲對於所有目的而言,線程都是死的。這很好,當你是絕對終止你的應用程序,並沒有什麼特別的線程。當你想要正常地終止操作時,不要使用Thread.Abort,使用單獨的mecanism來告訴它需要停止的線程。就像在這個例子中,設置一個靜態成員它會在這個時候檢查,下一個週期它就知道它必須在一個受控的地方停下來。

+0

我同意Thread.Abort是關閉一個線程的可怕方法。話雖如此,我有時在線程拒絕響應信號時使用它,並且控制線程已經不耐煩。 – 2010-05-14 13:38:10

1

那本書應該有說的是你永遠不應該使用Thread.Abort,因爲它有大量的問題。

因此,您所看到的任何非明顯或意外的行爲都應視爲您不應使用Thread.Abort

Thread.Abort的意思是告訴線程應用程序正在終止,你沒有很好地退出(我問過),現在你不得不死亡。對不起,但這就是它的方式。

就是這樣。你可以想到的每一個其他用例都會涉及到Thread.Abort應該有一個不同的解決方案,即句點。

合作方式通常是最好的辦法。使用一個信號(甚至像一個易變的布爾字段一樣簡單),並且當你希望線程退出時只需設置信號。定期在另一個線程中檢查此信號,並在設置時退出。或者......如果檢測到信號,甚至會發出異常。

只是從來沒有從外部使用Thread.Abort強加這一例外。

現在,如果你真的想知道如何處理這個異常,你可以發信號通知運行時你不希望這個異常自動傳播堆棧(ThreadAbortException是一種特殊情況)調用Thread.ResetAbort()

但是,您不應該做到這一點。