【发布时间】:2013-04-12 20:42:57
【问题描述】:
我有一个使用 execve 生成其他进程的程序:
s32 ret = execve( argv[0], argv.data(), (char* const*) req.posixEnv() );
稍后在循环中我调用 waitpid 来观察进程何时终止:
while( 1 )
{
readOutputFromChildProcess( pid );
int status;
s32 retPid = waitpid( pid, &status, WNOHANG );
if ( retPid < 0 )
{
if ( errno == ECHILD )
{
// I don't expect to ever get this error - but I do. why?
printf( "Process gone before previous wait. Return status lost.\n" );
assert(0);
} else {
// other real errors handled here.
handleError();
break;
}
}
if ( retPid == 0 )
{
waitSomeTime();
continue;
}
processValidResults( status );
break;
}
我已经大大简化了代码。我的理解是,一旦你产生了一个进程,进程表条目就会一直存在,直到调用者调用“waitpid”并获得大于零的返回值和有效的返回状态。
但在某些情况下似乎发生的是进程自行终止,当我调用 waitpid 时,它返回 -1,错误为 ECHILD
ECHILD 表示在我调用 waitpid 时,进程表中没有具有该 ID 的进程。所以要么我的 pid 无效 - 而且我已经仔细检查过 - 它是有效的。
或者 - 在这个过程完成后已经调用了 waitpid - 在这种情况下,我无法从这个过程中获取返回码。
程序是多线程的。我也检查过我没有太早调用waitpid。它发生在几次“等待”之后。
有没有其他方法可以在不调用 waitpid 的情况下清理进程表条目?我怎样才能确保我总是得到返回码?
@明确忽略 SIGCHLD:
好的,所以我知道明确忽略它会导致 waitpid() 失败。我没有明确地忽略它,但我确实设置了一些信号处理程序来捕获另一个地方的崩溃,如下所示:
void kxHandleCrashes()
{
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = abortHandler;
sigemptyset( &sa.sa_mask );
sigaction( SIGABRT, &sa, NULL );
sigaction( SIGSEGV, &sa, NULL );
sigaction( SIGBUS, &sa, NULL );
sigaction( SIGILL, &sa, NULL );
sigaction( SIGFPE, &sa, NULL );
sigaction( SIGPIPE, &sa, NULL );
// Should I add aline like this:
// sigaction( SIGCHLD, &sa, NULL );
}
【问题讨论】:
-
它发生在几次“等待”之后你是否试图在同一个进程上等待多次?
-
是的。这就是为什么我用NOHANG来称呼它。我需要能够定期返回我的线程以报告进度,并在调用进程挂起时终止它。
-
我认为你只能在一个孩子身上成功等待一次。之后内核清理进程信息,不留痕迹。
-
仅当回报为正时。如果您使用 NOHANG 调用并获得零回报,则不应清理该过程。
-
你可能会忽略
SIGCHLD吗?