【问题标题】:How do I write a program that tells when my other program ends? [closed]如何编写一个程序来告诉我的其他程序何时结束? [关闭]
【发布时间】:2008-09-24 06:14:22
【问题描述】:

如何编写一个程序来告诉我的其他程序何时结束?

【问题讨论】:

  • 如果我们知道您的工作环境、技术堆栈或语言可能会有所帮助...

标签: exit halt


【解决方案1】:

对一个不是你自己产生的程序执行 waitpid() 或 waitid() 的唯一方法是通过 ptrace 成为它的父级。

这是一个示例,说明如何在 posix 操作系统上使用 ptrace 临时成为另一个进程的父进程,然后等待该程序退出。作为副作用,您还可以获得退出代码,以及导致该程序退出的信号。:

#include <sys/ptrace.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>

int main(int argc, char** argv) {

    int pid = atoi(argv[1]);
    int status;
    siginfo_t si;

    switch (ptrace(PTRACE_ATTACH, pid, NULL)) {
        case 0:
            break;
        case -ESRCH:
        case -EPERM:
            return 0;
        default:
            fprintf(stderr, "Failed to attach child\n");
            return 1;
    }
    if (pid != wait(&status)) {
        fprintf(stderr, "wrong wait signal\n");
        return 1;
    }
    if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))  {
        /* The pid might not be running */
        if (!kill(pid, 0)) {
            fprintf(stderr, "SIGSTOP didn't stop child\n");
            return 1;
        } else {
            return 0;
        }
    }
    if (ptrace(PTRACE_CONT, pid, 0, 0)) {
        fprintf(stderr, "Failed to restart child\n");
        return 1;
    }

    while (1) {
        if (waitid(P_PID, pid, &si, WSTOPPED | WEXITED)) {
            // an error occurred.
            if (errno == ECHILD)
                return 0;
            return 1;
        }
        errno = 0;

        if (si.si_code & (CLD_STOPPED | CLD_TRAPPED)) {
            /* If the child gets stopped, we have to PTRACE_CONT it
             * this will happen when the child has a child that exits.
             **/
            if (ptrace(PTRACE_CONT, pid, 1, si.si_status)) {
                if (errno == ENOSYS) {
                    /* Wow, we're stuffed. Stop and return */
                    return 0;
                }
            }
            continue;
        }

        if (si.si_code & (CLD_EXITED | CLD_KILLED | CLD_DUMPED)) {
            return si.si_status;
        }
        // Fall through to exiting.
        return 1;
    }
}

【讨论】:

    【解决方案2】:

    在 Windows 上,我使用的一种技术是创建一个全局命名对象(例如使用 CreateMutex 的互斥锁),然后让监控程序打开同名的互斥锁并等待它(使用 WaitForSingleObject)。第一个程序一退出,第二个程序就获得了互斥体并知道第一个程序退出了。

    在 Unix 上,解决此问题的常用方法是让第一个程序将其 pid (getpid()) 写入文件。第二个程序可以监视这个 pid(使用 kill(pid, 0))来查看第一个程序是否已经消失。这种方法会受到竞争条件的影响,毫无疑问有更好的方法来解决它。

    【讨论】:

      【解决方案3】:

      如果您想生成另一个进程,然后在它运行时什么都不做,那么大多数高级语言已经内置了执行此操作的函数。例如,在 Perl 中,system 和反引号用于运行进程并等待它们完成,以及诸如 IPC::System::Simple 之类的模块,用于更容易确定程序是如何终止的,以及你是高兴还是悲伤那已经发生了。使用为您处理所有事情的语言功能方式比尝试自己做更容易。

      如果您使用的是 Unix 风格的系统,那么终止您分叉的进程将产生一个 SIGCHLD 信号。这意味着您的程序可以执行您的子进程正在运行的其他事情。

      捕捉 SIGCHLD 信号因您的语言而异。在 Perl 中,您可以像这样设置信号处理程序:

      use POSIX qw(:sys_wait_h);
      
      sub child_handler {
      
          while ((my $child = waitpid(-1, WNOHANG)) > 0) {
               # We've caught a process dying, its PID is now in $child.
               # The exit value and other information is in $?
          }
      
          $SIG{CHLD} \&child_handler;  # SysV systems clear handlers when called,
                                       # so we need to re-instate it.
      }
      
      # This establishes our handler.
      $SIG{CHLD} = \&child_handler;
      

      几乎可以肯定,CPAN 上的模块比上面的示例代码做得更好。您可以使用带有特定进程 ID 的 waitpid(而不是所有的 -1),如果您想让程序休眠直到其他进程完成,则可以不使用 WNOHANG

      请注意,当您在信号处理程序中时,可能会发生各种奇怪的事情。可能会出现另一个信号(因此我们使用 while 循环来捕获所有死进程),并且根据您的语言,您可能正在执行另一个操作!

      如果您在 Windows 上使用 Perl,那么您可以使用 Win32::Process 模块来生成一个进程,然后在生成的对象上调用 -&gt;Wait 以等待它终止。我不熟悉Win32::Process 的所有内容,但是您应该能够等待0(或1 等待一毫秒)的长度来检查进程是否已经死亡。

      在其他语言和环境中,您的里程可能会有所不同。请确保当您的其他进程死亡时,您检查它是如何死亡的。让子进程因为用户杀死它而死亡,通常需要与它因为成功完成任务而退出不同的响应。

      一切顺利,

      保罗

      【讨论】:

        【解决方案4】:

        你在 Windows 上吗?如果是这样,以下应该可以解决问题 - 您需要传递进程 ID:

          bool WaitForProcessExit( DWORD _dwPID )
          { 
             HANDLE hProc = NULL;
             bool bReturn = false;
        
             hProc = OpenProcess(SYNCHRONIZE, FALSE, _dwPID);
        
             if(hProc != NULL)
             {
               if ( WAIT_OBJECT_0 == WaitForSingleObject(hProc, INFINITE) )
               {
                 bReturn = true;
               }
             }
        
             CloseHandle(hProc) ;
          }
        
          return bReturn;
        }
        

        注意:这是一个阻塞函数。如果您想要非阻塞,则需要将 INFINITE 更改为较小的值并在循环中调用它(可能保持 hProc 句柄打开以避免在相同 PID 的不同进程上重新打开)。

        另外,我没有时间测试这段源代码,但我从我的一个可以工作的应用程序中提取了它。

        【讨论】:

          【解决方案5】:

          大多数操作系统通常是同一类东西....

          您记录相关程序的进程 ID,并通过定期查询活动进程来监控它

          至少在 Windows 中,您可以触发关闭事件来执行此操作...

          【讨论】:

            【解决方案6】:

            嗯,你不能,考虑到它的性质,这是一项不可能完成的任务。

            假设您有一个程序 foo,它将另一个程序 foo-sub 作为输入。

            Foo {
             func Stops(foo_sub) { run foo_sub; return 1; }
            }
            

            这一切的问题都是相当简单的设计,如果 foo-sub 是一个永远不会结束的程序,那么 foo 本身就永远不会结束。没有办法从外部判断是 foo-sub 还是 foo 是导致程序停止的原因,以及是什么决定了您的程序是否只需要一个世纪才能运行?

            基本上这是计算机无法回答的问题之一。如需更完整的概述,维基百科有一篇关于 this 的文章。

            【讨论】:

              【解决方案7】:

              这称为“停机问题”,无法解决。 见http://en.wikipedia.org/wiki/Halting_problem

              【讨论】:

                【解决方案8】:

                如果你想在不执行的情况下分析一个程序,那就是无法解决的问题。

                【讨论】:

                  猜你喜欢
                  • 2022-09-27
                  • 1970-01-01
                  • 2014-11-18
                  • 2022-01-23
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-10-31
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多