【问题标题】:Kill child process from main app从主应用程序中杀死子进程
【发布时间】:2010-01-20 16:23:36
【问题描述】:

我有一个在后台运行 python 脚本的 Delphi 服务器(它们的运行类似于“python Sync.py **params**”)。

这个脚本可以做一些事情,比如连接到外部服务器、打开 ssh 连接和他们可以挂起的可怕的东西。

我需要检测它们是否挂起,然后将其杀死。此外,如果服务器已关闭,并且也想终止进程(如果没有,Delphi 服务器挂起,从桌面消失但在后台不可见。如果再次执行服务器,这会导致稍后出现问题)。

先试试不行。该进程被终止,但如果我关闭应用程序,服务器就会挂起。

所以问题是是否存在更可靠/更好的方法来杀死子进程。

现在,我保存他们的 Handle 和 GetTickCount ,如下所示:“handle=tickcount”,然后每 4 秒运行一次 TTimer 并查看进程是否超时:

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;

【问题讨论】:

  • 好的,但问题是什么?

标签: multithreading delphi winapi


【解决方案1】:

我不明白您是如何检查进程是否没有响应的。如果您的子进程有GUI,那么您可以使用SendMessageTimeOut API 函数向属于该进程的窗口之一发送消息,并检查该消息是否在指定时间内被它处理。

这是一个示例代码,它使用我的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;

【讨论】:

  • 我不检查,如果时间太长,我只是超时。
  • 好的,你可以把你的进程超时代码放在上面代码的IsProcoessUnresponsive函数中。
  • 链接到您的 TProcessInfo 不再有效,导致该解决方案不可行。
【解决方案2】:

调用TerminateProcess 是杀死进程的唯一可靠方法。

还有更优雅的方法,但要使用它们,您需要了解进程期望如何被告知关闭。 GUI 进程通常希望它们的主窗口关闭,因此您需要确定这些窗口是哪些窗口,然后向它们发送wm_Close 消息。批处理模式控制台程序可能希望您按 Ctrl+C;交互式控制台程序可能有一个您应该键入的特殊命令。

所有这些都假设进程仍在响应输入。如果进程挂起,它可能永远不会看到“优雅”命令,因此由TerminateProcess 强制终止是唯一剩下的选项。

如果我是你,我会避免在错误消息中使用术语僵尸进程。你正在处理的根本不是僵尸。 Zombies 是已 终止的进程,但某些其他进程仍有打开的句柄。您正在做的是检测运行时间过长且超时的进程。它们不一定是挂起的进程,只是耗时超过分配时间的进程。因此,只需在您的错误消息中说那个:“进程已超时。” (如果您可以记录一些有意义的哪个进程的指示,那就更好了。)

【讨论】:

  • 您可以先使用其他方式(例如发送 WM_QUIT),并且只要您有进程句柄,您就可以使用指定的超时执行 WaitForSingleObject。如果等待返回超时,你真的可以终止进程作为最后的手段。
猜你喜欢
  • 1970-01-01
  • 2013-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-08
  • 2012-11-01
  • 1970-01-01
相关资源
最近更新 更多