2010-05-05 85 views
2

我正在使用重定向的I/O與模擬器可執行文件進行通信,從VB.NET GUI控制一箇舊的FORTRAN模擬器。 GUI彈出一個帶有進度條,估計時間和「停止」按鈕的「狀態」窗口(Button_Stop)。.NET Process.Kill()以安全的方式

現在,我想Button_Stop立即終止仿真程序。執行此操作的顯而易見的方法是在Child Process對象上調用Kill()。如果在進程退出後這樣做會發出異常,但是我可以在嘗試終止進程之前測試該進程是否已退出,對不對?

OK,所以我做的是單擊按鈕時以下幾點:

If Not Child.HasExited Then 
    Child.Kill() 
    Button_Stop.Enabled = False 
End If 

但是,如果過程發生的測試和調用Kill()之間退出呢?在那種情況下,我得到一個例外。

發生在我接下來的事情是,我可以在Process.Exited事件處理程序做Button_Stop.Enabled = False,從而防止Button_Stop.Clicked處理程序Child.Kill()電話。但由於Process.Exited處理程序被調用在不同的線程中,仍有以下可能的交織:

  1. 子進程退出。
  2. Process.Exited火災,呼籲Invoke安排上Button_StopButton_Stop.Enabled = False
  3. 用戶點擊,引發Child.Kill()
  4. Button_Stop.Enabled = False實際情況。

一個例外然後一步拋出3.

如何殺過程中沒有任何競爭條件?我在想這個完全錯誤嗎?

回答

3

只需捕獲異常,並關閉按鈕finally

Try      
    Child.Kill() 
Catch ex As Exception 
    MsgBox(ex.ToString()) 
Finally 
    Button_Stop.Enabled = False 
End Try 

相反捕獲所有類型的異常的它當然會更好,只趕上InvalidOperationExceptionWin32Exception這些過程是否終止拋出或已經退出。

如果程序中發生異常,並且您應該設計程序以避免異常,您可能認爲這是一件「壞事」。但是,有不同類型的異常和異常處理,其中一些是不好的設計決定,而另一些(如本文所述)則是強制性的,因爲異常(即終止另一個進程)的原因超出了您的控制範圍。

如果你想繼續讀下去,我建議你在不同類型的異常埃裏克Lipperts帖子:

Fabulous Adventures In Coding: Vexing exceptions

+0

這將工作,但它似乎很尷尬,因爲它s意味着在地板上拋出異常。構建在正常操作中永遠不會遇到異常的程序不是很好的做法嗎? – 2010-05-05 21:40:48

+0

@Orbode:你可能看起來很尷尬,但是這樣的外部異常應該使用try-catch塊來處理。進一步閱讀:http://blogs.msdn.com/ericlippert/archive/2008/09/10/vexing-exceptions.aspx – 2010-05-05 21:42:18

+0

@Orborde這只是推薦的事情,如果你捕捉.NET異常。在這種情況下,您正在捕獲非託管的異常,因此可以捕獲所有內容 – 2010-05-05 21:47:57

1

您可以P/Invoke到TerminateProcess它不會拋出,如果該過程已經退出:

Sub Main() 
    Dim p = Process.Start("C:\Windows\system32\notepad.exe") 
    Thread.Sleep(1000) 
    TerminateProcess(p.Handle, 0) 
    TerminateProcess(p.Handle, 0) ''# This call won't throw, it will just fail silently. 
End Sub 

<DllImport("kernel32.dll", SetLastError:=True)> 
Private Function TerminateProcess(ByVal hProcess As IntPtr, ByVal uExitCode As UInteger) As <MarshalAs(UnmanagedType.Bool)> Boolean 
End Function 
+0

實際上,如果返回值爲零或進程句柄不再有效,則Process.Kill()簡單地調用TerminateProcess並拋出。但是,不需要像樣例中那樣調用TerminateProcess兩次。 – 2010-05-05 21:53:11

+1

沒錯,只是證明它不會拋出:)編輯清晰。 – 2010-05-05 21:54:31