.NET Process.Kill () in a safe way

I control a creaky old FORTRAN simulator from the VB.NET GUI using redirected I / O to communicate with the simulator executable. The GUI displays a status window with a progress bar, estimated time, and a STOP button ( Button_Stop

).

Now I want to Button_Stop

terminate the simulator process immediately. The obvious way to do this is to call Kill()

on a Child

Process object . This throws an exception if it was executed after the process exited, but I can check if the process exited before trying to kill it, right?

OK, so when the button is clicked, I do the following:

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

      

However, what happens if the process ends with a test and a call to Kill()

? In this case, I am getting an exception.

The next thing that had to happen was what I can execute Button_Stop.Enabled = False

in the event handler Process.Exited

and thus prevent the call Child.Kill()

in the handler Button_Stop.Clicked

. But since the handler Process.Exited

is called on a different thread, that still leaves the following possible interleaving:

  • The exit of the child process.
  • Process.Exited

    fires, calls Invoke

    to scheduleButton_Stop.Enabled = False

  • User clicks Button_Stop

    , launchesChild.Kill()

  • Button_Stop.Enabled = False

    actually happens.

In step 3, an exception will be thrown.

How can I kill a process without any race conditions? Am I thinking about this completely wrong?

+2


a source to share


2 answers


Just catch the exception and disable the button in finally

:

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

      

Instead of catching all types of exceptions, of course, it would be better to only catch InvalidOperationException

and Win32Exception

, since they are thrown if the process exits or has already terminated.



You are probably thinking that it is "bad" for exceptions to occur in a program and that you must design your program to eliminate exceptions altogether. However, there are different types of exceptions and exception handling, some of which are bad design decisions and others - like this one - are mandatory because the reason for the exception (i.e. terminating another process) is beyond control.

If you want to read further, I recommend Eric Lipperts' posts on different kinds of exceptions:

Fabulous Coding Adventures: The Vexing Exception

+3


a source


You can P / Invoke in TerminateProcess

, which won't throw if the process has already exited:



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

      

+1


a source







All Articles