.NET Process.Kill () безопасным способом - PullRequest
2 голосов
/ 06 мая 2010

Я управляю скрипучим старым симулятором FORTRAN из графического интерфейса VB.NET, используя перенаправленный ввод-вывод для связи с исполняемым файлом симулятора. Графический интерфейс пользователя открывает окно «Состояние» с индикатором выполнения, расчетным временем и кнопкой «СТОП» (Button_Stop).

Теперь я хочу, чтобы Button_Stop немедленно завершил процесс симулятора. Очевидный способ сделать это - вызвать Kill() для объекта Child Process. Это дает исключение, если оно выполнено после завершения процесса, но я могу проверить, завершен ли процесс, прежде чем пытаться его уничтожить, верно?

ОК, поэтому, когда я нажимаю кнопку, я делаю следующее:

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

Однако, что если произойдет выход из процесса между тестом и вызовом Kill()? В этом случае я получаю исключение.

Следующее, что мне пришло в голову, было то, что я могу сделать Button_Stop.Enabled = False в обработчике Process.Exited и, таким образом, предотвратить вызов Child.Kill() в обработчике Button_Stop.Clicked. Но поскольку обработчик Process.Exited вызывается в другом потоке, все равно остается следующее возможное чередование:

  1. Дочерний процесс завершается.
  2. Process.Exited пожары, звонки Invoke для планирования Button_Stop.Enabled = False
  3. Пользователь нажимает Button_Stop, вызывая Child.Kill()
  4. Button_Stop.Enabled = False на самом деле происходит.

На шаге 3 будет выдано исключение.

Как убить процесс без каких-либо условий гонки? Я думаю об этом совершенно неправильно?

Ответы [ 2 ]

3 голосов
/ 06 мая 2010

Просто перехватите исключение и отключите кнопку в finally:

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

Вместо перехвата всех типов исключений, конечно, было бы лучше перехватывать только InvalidOperationException и Win32Exception, поскольку они выбрасываются, если процесс завершается или уже завершился.

Вы, вероятно, думаете, что это "плохо", если в программе возникают исключения, и что вам следует разрабатывать свою программу, чтобы вообще избегать исключений. Однако существуют различные типы исключений и обработки исключений, некоторые из которых являются неправильными проектными решениями, а другие - как этот - являются обязательными, поскольку причина исключения (то есть прекращение другого процесса) находится вне вашего контроля.

Если вы хотите читать дальше, я рекомендую вам сообщения Эрика Липперта о различных исключениях:

Невероятные приключения в кодировании: исключение Vexing

1 голос
/ 06 мая 2010

Вы можете 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...