1

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 );
}
4

2 に答える 2

4

同様の問題がありました-waitpidはECHLDで失敗するだけです。子プロセスが実行されていましたが、SIGCHLD ハンドラー (デフォルトのハンドラーが配置されています) に触れていませんでしたが、毎回 waitpid で ECHLD を取得していました。

数時間の調査の後、私が子供たちを分岐させ、次に親を悪魔化し (分岐させた)、事実上すべての子供たちを孤児にしたことが判明しました..

子をフォークする前に親のデーモン化が発生するように移動したところ、すべてが問題なく動作し始めました。

したがって、この不思議な ECHLD エラーが発生し、SIGCHLD シグナル ハンドラーをいじっていない場合は、それらの子がまだ実際に自分の子であるかどうか、および子の PPID が親の PID と等しいかどうかを確認してください。

于 2014-06-26T00:17:42.440 に答える
0

あなたのプログラム例には、重要な情報が欠けています: How do you declare errno?

を必ず含める必要がありますerrno.h

Thread-safety および POSIX.1の errnoセクションの再定義を参照してください。

于 2013-04-12T20:53:47.950 に答える