2010-01-20 2 views
1

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

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

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

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

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

Теперь, я сохранить их Handle и их GetTickCount, как это: «ручка = 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; 
+0

Хорошо, но в чем вопрос? –

ответ

0

Я не понимаю как вы проверяете, не реагирует ли процесс. Если ваш дочерний процесс имеет графический интерфейс, вы можете отправить сообщение в одно из окон, принадлежащих процессу, с помощью функции 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; 
+0

Я не проверяю, я просто затягиваю процесс, если слишком долго. – mamcx

+0

ОК, вы можете поместить свой код для тайм-аута процесса в функции IsProcoessUnresponsive в приведенном выше коде. – vcldeveloper

+0

Ссылка на ваш TProcessInfo больше не работает, что делает решение неработоспособным. – jep

0

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

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

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

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

+0

Вы можете использовать другие способы сначала (например, отправить WM_QUIT) и как lng, поскольку у вас есть дескриптор процесса, который вы можете сделать WaitForSingleObject с заданным таймаутом. Если ожидание вернется с временным графиком, вы можете действительно прекратить процесс в крайнем случае. –

Смежные вопросы