SIGCHLDとwaitpid()またはwait()の関係は何ですか?

SIGCHLDとwaitpid()またはwait()の関係は何ですか?

私が正しい場合、プロセスは関数を呼び出して子プロセスが終了または停止するのを待ちますwaitpid()wait()

waitpid()SIGCHLD信号とor関数の関係は何ですかwait()

  • プロセスwaitpid()がまたはwait()関数を呼び出すときに子プロセスがシャットダウン/停止されるまで(SIGCHLD信号を送信する前と同じ)、プロセスはそれ自体が停止することは正しいですか?

    (シグナルが送信されるまで現在のプロセスを中断します。SIGCHLDが送信されるまでを除いて同様であるかどうか疑問にpause()思います。)waitpid()

  • SIGCHLDが呼び出しによって中断されたプロセスに送信されるとき、waitpid()SIGCHLDハンドラの実行と中断から再開の間の順序は何ですかwaitpid()
    (次のコンピュータシステムの例では:プログラマの観点からSIGCHLDハンドラを呼び出しますwaitpid()。)

ありがとうございます。

void handler(int sig)
{
  int olderrno = errno;

  while (waitpid(-1, NULL, 0) > 0) {
    Sio_puts("Handler reaped child\n");
  }
  if (errno != ECHILD)
    Sio_error("waitpid error");
  Sleep(1);
  errno = olderrno;
}

int main()
{
  int i, n;
  char buf[MAXBUF];

  if (signal(SIGCHLD, handler1) == SIG_ERR)
    unix_error("signal error");

  /* Parent creates children */
  for (i = 0; i < 3; i++) {
    if (Fork() == 0) {
      printf("Hello from child %d\n", (int)getpid());
      exit(0);
    }
  }

  /* Parent waits for terminal input and then processes it */
  if ((n = read(STDIN_FILENO, buf, sizeof(buf))) < 0)
    unix_error("read");

  printf("Parent processing input\n");
  while (1)
    ;

  exit(0);
}

答え1

wait()は1970年代の無駄なUNIXシステムコールであり、waitpid()1980年代の無駄なUNIXシステムコールです。

waitid()1988年には高度なインターフェースが導入されました。

signal()また、1970年代の古いインターフェースでもあります。最も近いインターフェイスが呼び出され、sigaction()信号の動作を制御できます。あなたの場合、一般的な通貨は次のとおりです。

    struct sigaction sa; 

    sa.sa_sigaction = handler; 
    sigemptyset(&sa.sa_mask); 
    sa.sa_flags = SA_RESTART|SA_SIGINFO; 

    sigaction(SIGCHLD, &sa, NULL); 

に追加すると、SA_NOCLDWAITまったくsa.sa_flags呼び出す必要はなく、wait*()システムはwait*()呼び出されるまでゾンビプロセスを維持しません。

追加すると、SA_NOCLDSTOPcildプロセスが終了したときにSIGCHLDハンドラは呼び出されません。

SIGCHLDaが生成されると、関数が呼び出されます。

void handler(int sig, siginfo_t *sip, void *context)

子プロセスが死んだとき。このパラメータはsigシグナル番号で埋められ、2番目のパラメータは以下のように呼び出しSIGCHLDで得られたのと同じ情報で埋められます。waitid()

struct siginfo si;

ret = waitid(P_PID, pid, &si, WEXITED|WSTOPPED|WTRAPPED);

したがって、子プロセスの状態に興味がない場合はシステムに通知することができ、子プロセスを呼び出すことには興味がありませんが、wait*()まだプロセスの状態を取得したい場合は、システムに通知して情報を使用できます。シグナルハンドラ関数の2番目のパラメータにあります。

子プロセスが終了してstruct siginfo確認されると、次のフィールドが入力されます。

si.si_signo   /* The signal number SIGCHLD */
si.si_code    /* The reason for the child to exit */
si.si_status  /* Either the parameter to exit(r) or signal number */
si.si_pid     /* The process id of the child that died */

si.si_code値が含まれるCLD_EXITEDと、完全なsi.si_status32ビットコードが含まれます(POSIXシステムの場合)exit()

、またはが含まれているsi.si_code場合は、状態変更を引き起こした信号番号が含まれます。CLD_KILLEDCLD_DUMPEDCLD_TRAPPEDCLD_STOPPEDCLD_CONTINUEDsi.si_status

答え2

インストールされている場合、カーネルはサブプロセスの状態が変更されると(通常はシャットダウン)、プロセスはシグナルハンドラを呼び出しますが、デフォルトではサブプロセスを取得しません。子プロセスを収集するには、ハンドラの内側または外側でwait(2)またはwaitpid(2)を呼び出す必要があります。 SIGCHLDハンドラをインストールするときにsigaction(2)のオプションとしてSA_NOCLDWAITを指定すると、シグナルハンドラが渡された後にカーネルが自動的に子プロセスを取得し、それを取得するためにwait(2)呼び出しを必要としません。

SIGCHLD に関連する sigaction(2) のマニュアルページの SA_NOCLDSTOP および SA_NOCLDWAIT オプションの説明を参照してください。

また、SA_SIGINFOを指定して3つの引数で構成されるシグナルハンドラを使用できるようにするsignal(2)の代わりにsigaction(2)の使用を検討してください。 siginfo_t構造参照には、SIGCHLDが渡される理由に関する追加の有用な情報が含まれています。

答え3

コメントするのに十分なポイントはありませんが、これはあなたの質問に答えるでしょう。

https://www.tutorialspoint.com/unix_system_calls/waitpid.htm#:~:text=%20waitpid()%20system%20call,options%20argument%2C%20as%20Description%20 は次のとおりです。

発生した信号は、SIGCHLDの例で対応する特定の信号タイプに対して設定されたハンドラ機能をトリガします。

ここに例があります。 https://stackoverflow.com/questions/13792900/signal-and-sigchld-what-does-it-do

上記のリンクからわかるように、wait()がハンドラの内部にある必要はありません。

子プロセスが終了するのを待ちます。

したがって、基本的に直接的な関係はありません。分岐したサブプロセスが終了すると、SIGCHLD信号が生成され、wait()はサブプロセスが適切に終了するのを待ちます。

関連情報