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

waitpid returns ECHILD - but pid was valid

本文关键字:有效 pid 但是 返回 ECHILD waitpid      更新时间:2023-10-16

我有一个程序,生成其他进程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 );
}

我有类似的问题- waitpid将失败与ECHLD。子进程正在运行,我没有接触SIGCHLD处理程序(默认处理程序),但每次仍然在waitpid上获得ECHLD。

经过几个小时的调查发现,原来是我把孩子分出来,然后妖魔化父母(父母分出来),这实际上把所有的孩子都变成了孤儿。

我将父进程的守护进程移到fork子进程之前,这样一切就开始完美地工作了。

如果你得到这个神秘的ECHLD错误,你没有弄乱SIGCHLD信号处理程序-检查这些孩子是否仍然是你的孩子,孩子的PPID等于父母的PID

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

您应该确保包含errno.h

请参考线程安全和POSIX.1中errno的重新定义一节。