我有一个使用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的情况下,是否还有其他方法可以清理进程表条目?我如何确保始终获得返回码?
@Explicitly忽略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 );
}
答案 0 :(得分:4)
我有类似的问题 - waitpid会因ECHLD而失败。子进程正在运行,我没有触及SIGCHLD处理程序(默认处理程序),但每次都在waitpid上获取ECHLD。
经过几个小时的调查后,我把孩子分开了,然后妖魔化了父母(分叉了),这有效地将所有孩子变成了孤儿......
我将父母守护程序移到了分叉之前,一切都开始完美地运作。
因此,如果您收到这个神秘的ECHLD错误,并且您没有弄乱SIGCHLD信号处理程序 - 请检查这些孩子是否仍然是您的孩子,并且孩子的PPID等于父母的PID。
答案 1 :(得分:0)