2009-06-10 36 views
7

我有一個線程出去並嘗試建立連接。在線程中,我打電話給第三方庫。有時候,這個調用會掛起,並且永遠不會返回。在UI線程上,我希望能夠通過中止線程來取消連接嘗試,該線程應該中止對第三方庫的掛起呼叫。你如何處理有掛斷電話的線程?

我已經調用了Thread.Abort,但現在已經讀取了Thread.Abort僅在控件返回到託管代碼時才起作用。我觀察到這是真的,因爲線程永遠不會中止,而且我現在已經坐在Thread.Join上十分鐘了。我該如何處理這個懸掛的線程?我是否應該將參考歸零並繼續前進?我想盡可能地乾淨 -

回答

3

此功能在您的第三方庫沒有超時取消功能?如果是這樣,那是非常糟糕的設計。還有的不會是任何漂亮的解決方案在這裏,記錯...

不幸的是,有沒有辦法,你要避開它,短期使用Win32 API手工殺掉線程,這肯定是不去幹淨。但是,如果這個第三方庫沒有給你任何其他選擇,這可能是要做的事情。 TerminateThread函數是你想要使用的,但要注意警告!要獲得線程ID傳遞給此函數,您必須使用另一個Win32 API調用(Thread類不直接公開它)。此處的方法是在託管線程方法的開始將volatile類變量的值設置爲GetCurrentThreadId的結果,然後稍後使用此線程ID來終止該線程。

4

隨機想法:我想知道如果你可以編寫第二個程序集作爲一個小型控制檯EXE執行此通信...啓動它與Process.Start並通過文件系統或通過攔截標準輸出。然後如果它掛起,你可以殺死進程。

有點苛刻,也許 - 顯然它有產卵過程的開銷 - 但它至少應該有可能殺死它。

+4

「從軌道上取下並燒燬網站 - 這是確保的唯一方法。」事實上,你是對的;這是終止行爲不當的代碼的唯一保證安全的方法。 Thread.Abort不保證實際放棄行爲不端的線程;一個真正表現不佳的線程可以劫持中止。即使取下一個appdomain也不一定做你想要的。如果你絕對肯定不得不殺死行爲不端的代碼,那麼你需要將它隔離到一個可驅動的過程。 – 2009-06-11 06:39:02

+0

謝謝里普利...我的意思是...埃裏克;-p(我會給哈德森的回覆,但我不得不使用我自己的版主工具...) – 2009-06-11 08:00:21

1

受管理的線程不能直接阻止本地線程。因此,如果調用在本地代碼中被阻塞,那麼您可以做的最好的方法是進行託管線程檢查,然後在它返回時終止。如果它永遠不會返回,也許有一個timemout的調用版本?

如果沒有,註銷線程(通過win32)中通常不是個好主意......

+0

電話永遠不會返回,這就是爲什麼我有人爲地終止線程。 – MedicineMan 2009-06-10 23:01:22

2

不知道這是否會或可以接受,但它的價值。

[DllImport("kernel32.dll")] 
private static extern bool TerminateThread (Int32 id, Int32 dwexit); 

documentation

TerminateThread是隻能在最極端的情況下使用危險的功能。只有當您確切知道目標線程正在執行什麼操作時,才應該調用TerminateThread,並且您可以控制目標線程在終止時可能正在運行的所有代碼。例如,TerminateThread可能導致以下問題:

  • 如果目標線程擁有臨界區,臨界區將不會被釋放。
  • 如果目標線程正在從堆中分配內存,堆鎖將不會被釋放。
  • 如果目標線程在終止時正在執行某些kernel32調用,則線程進程的kernel32狀態可能不一致。
  • 如果目標線程正在操作共享DLL的全局狀態,則DLL的狀態可能會被破壞,從而影響DLL的其他用戶。
-1

不是一個很好的解決方案,無限期地等待一個線程(使用任何語言),特別是如果你正在進行外部調用。始終使用超時連接或自旋鎖來監視共享的原子變量的狀態,直到它發生更改或達到超時。我不是C#的人,但這些都是健全的併發做法。