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

时间:2008-09-24 06:14:23

标签: exit halt

如何编写一个程序,告诉我的其他程序什么时候结束?

8 个答案:

答案 0 :(得分:11)

对不是由你自己生成的程序执行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;
    }
}

答案 1 :(得分:4)

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

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

答案 2 :(得分:4)

如果你想生成另一个进程,然后在它运行时什么也不做,那么大多数高级语言已经有内置插件来执行此操作。例如,在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上的模块比上面的示例代码做得更好。您可以将waitpid与特定进程ID一起使用(而不是对所有进程使用-1),如果您希望让程序休眠直到另一个进程完成,则可以使用WNOHANG

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

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

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

一切顺利,

答案 3 :(得分:2)

你在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的不同进程上重新打开)。

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

答案 4 :(得分:0)

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

您记录有问题的程序的进程ID,并通过定期查询活动进程来监视它

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

答案 5 :(得分:-2)

嗯,你不能,鉴于它的本质,这是一项不可能完成的任务。

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

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

这一切的问题都是相当简单的设计,如果foo-sub是一个永不结束的程序,foo本身永远不会结束。没有办法从外面告诉foo-sub或foo是导致程序停止的原因,是什么决定你的程序是否需要一个世纪才能运行?

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

答案 6 :(得分:-3)

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

答案 7 :(得分:-3)

如果你想分析一个没有执行的程序而不是无法解决的问题。