Убить дочерний процесс из основного приложения - PullRequest
1 голос
/ 20 января 2010

У меня есть сервер Delphi, который запускает скрипты Python в фоновом режиме (они работают аналогично "python Sync.py **params**").

Эти сценарии могут выполнять такие действия, как подключение к внешним серверам, открывать ssh-соединения и делать страшные вещи, где они могут зависать.

Мне нужно обнаружить, если они висят, и убить его. Кроме того, если сервер закрыт, и вы хотите завершить процесс (в противном случае сервер Delphi зависает, исчезает с рабочего стола, но становится невидимым в фоновом режиме. Эта проблема возникает позже, если сервер запускается снова).

Сначала попробуйте не работать. Процесс будет убит, но если я закрою приложение, сервер зависнет.

Таким образом, вопрос в том, существует ли более надежный / лучший способ убить дочерний процесс.

Теперь я сохраняю их дескриптор и их GetTickCount, например: «handle = tickcount», затем запускаю их с TTimer каждые 4 секунды и проверяю, истекло ли время ожидания процесса:

procedure TfrmMain.CheckProcess(Sender: TObject);
var
  i: Integer;
  Fecha:TDateTime;
  start, stop, elapsed,Handle : cardinal;
begin
  stop := GetTickCount;

  for i := (FProcesos.Count - 1) downto 0 do
  begin
      start := StrToInt( FProcesos.ValueFromIndex[i] );
      elapsed := stop - start; //milliseconds
      //Esta muerto el proceso??
      if ((elapsed>TIMEOUT_PROCESS) or (FTimer.Enabled=False)) then
      begin
        Handle := StrToInt( FProcesos.Names[i] );

        TerminateProcess(Handle,0);
        CloseHandle( Handle );

        FProcesos.Delete( i );
        LogMsg('A process timed out!',msgError);
      end;
  end;//for
end;

Ответы [ 2 ]

0 голосов
/ 20 января 2010

Вызов TerminateProcess - единственный надежный способ убить процесс.

Есть более изящные способы, но чтобы использовать их, вам нужно знать кое-что о том, как процесс ожидает, что его закроют. Процессы с графическим интерфейсом обычно ожидают закрытия своих основных окон, поэтому вам необходимо выяснить, какие это окна, а затем отправлять им wm_Close сообщения. Консольные программы в пакетном режиме могут ожидать, что вы нажмете Ctrl + C; В программах интерактивной консоли может быть специальная команда, которую вы должны вводить.

И все это предполагает, что процесс все еще отвечает на ввод. Если процесс завис, он может никогда не увидеть команду «graceful», поэтому принудительное завершение с помощью TerminateProcess - единственный оставшийся вариант.

Если бы я был вами, я бы не использовал термин процесс зомби в сообщении об ошибке. То, с чем вы имеете дело, вовсе не зомби. Зомби - это процессы, для которых завершено , но для какого-то другого процесса все еще есть открытый дескриптор. То, что вы делаете, это обнаружение процессов, которые выполнялись слишком долго и истекло . Это не обязательно зависшие процессы, просто процессы, которые занимают больше времени, чем выделенное время. Так что просто скажите , что в своем сообщении об ошибке: «Время процесса истекло». (Еще лучше, если вы можете записать какое-то значимое указание на , который обрабатывает.)

0 голосов
/ 20 января 2010

Я не понял, как вы проверяете, не отвечает ли процесс.Если ваши дочерние процессы имеют графический интерфейс пользователя, вы можете отправить сообщение в одно из окон, принадлежащих процессу, используя API-функцию SendMessageTimeOut , и проверить, обрабатывается ли им сообщение в течение указанного времени или нет.

Вот пример кода, который использует мой TProcessInfo для перечисления всех дочерних процессов для текущего потока и завершения любого из них, который не отвечает - пожалуйста, обратите внимание, что, поскольку я не мог понятьВаш метод обнаружения не отвечающих процессов, функция IsProcessUnResponsive не реализована в моем коде и оставлена ​​для вас:

function IsProcessUnResponsive(const ProcessID: Cardinal): Boolean;
begin
  //Use your own technique for determining if a process is not responsive.
end;

procedure TerminateUnResponsiveProcesses;
var
  Process: TProcessItem;
  ProcessInfo : TProcessInfo;
begin
  ProcessInfo := TProcessInfo.Create(nil);
  try
    for Process in ProcessInfo.RunningProcesses do
    begin
      if Process.ParentProcessID = GetCurrentProcessId then
        if IsProcessUnResponsive(Process.ProcessID) then
          Process.TerminateProcess;    
    end;
  finally
    ProcessInfo.Free;
  end;
end;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...