waitpid返回ECHILD - 但是pid是有效的

时间:2013-04-12 20:42:58

标签: c++ c linux process posix

我有一个使用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 );
}

2 个答案:

答案 0 :(得分:4)

我有类似的问题 - waitpid会因ECHLD而失败。子进程正在运行,我没有触及SIGCHLD处理程序(默认处理程序),但每次都在waitpid上获取ECHLD。

经过几个小时的调查后,我把孩子分开了,然后妖魔化了父母(分叉了),这有效地将所有孩子变成了孤儿......

我将父母守护程序移到了分叉之前,一切都开始完美地运作。

因此,如果您收到这个神秘的ECHLD错误,并且您没有弄乱SIGCHLD信号处理程序 - 请检查这些孩子是否仍然是您的孩子,并且孩子的PPID等于父母的PID。

答案 1 :(得分:0)

您的程序示例缺少一条重要信息:您如何声明errno

您应该确保包含errno.h

请参阅Thread-safety and POSIX.1 errno重新定义部分。