SIGCHLD 和 waitpid() 或 wait() 之间有什么关系?

SIGCHLD 和 waitpid() 或 wait() 之间有什么关系?

如果我是正确的,进程会通过调用waitpid()wait()函数来等待其子进程终止或停止。

waitpid()SIGCHLD信号和or函数有什么关系wait()

  • 当进程调用waitpid()wait()函数时,进程会自行挂起直到子进程终止/停止(这与向其发送 SIGCHLD 信号之前相同)是否正确?

    pause()挂起当前进程,直到有任何信号发送给它。所以我想知道是否waitpid()类似,除了直到 SIGCHLD 发送给它?)

  • 当 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()是 20 世纪 70 年代的过时 UNIX 系统调用,也是waitpid()1980 年代的过时 UNIX 系统调用。

waitid()1988年,推出了高级界面。

signal()也是 20 世纪 70 年代的过时界面。最近的接口被调用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_NOCLDSTOP,则当 cild 进程退出时,将不会调用 SIGCHLD 处理程序。

如果SIGCHLD生成了 a,则会调用一个函数:

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

当子进程死亡时。该参数sig填充了信号编号SIGCHLD,第二个参数填充了与调用 获得的相同信息waitid(),如下所示:

struct siginfo si;

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

因此,如果您对子进程的状态不感兴趣,则可以告诉系统,如果您对调用不感兴趣wait*(),但仍想获取进程状态,则可以告诉系统并使用第二个中的信息信号处理函数的参数。

当子进程死亡并被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_status(在 POSIX 系统上)包含完整的 32 位代码exit()

如果si.si_code包含CLD_KILLEDCLD_DUMPEDCLD_TRAPPEDCLD_STOPPEDCLD_CONTINUEDsi.si_status包含导致状态更改的信号编号。

答案2

如果安装了,当子进程改变状态(通常是退出)时,内核会在进程中调用信号处理程序,但默认情况下,它不会获取子进程。仍然需要从处理程序内部或外部调用 wait(2) 或 waitpid(2) 才能收获子进程。如果在安装 SIGCHLD 处理程序时将 SA_NOCLDWAIT 指定为 sigaction(2) 的选项,则内核将在信号处理程序交付后自动获取子进程,并且不需要 wait(2) 调用来获取。

请参阅 sigaction(2) 手册页中对 SA_NOCLDSTOP 和 SA_NOCLDWAIT 选项的讨论,因为它们与 SIGCHLD 相关。

另外,请考虑使用 sigaction(2) 而不是 signal(2),并允许您通过指定 SA_SIGINFO 使用三参数信号处理程序。 siginfo_t 结构参考将包含有关为何传递 SIGCHLD 的附加有用信息。

答案3

我没有足够的观点来发表评论,但这应该可以回答你的问题。

https://www.tutorialspoint.com/unix_system_calls/waitpid.htm#:~:text=%20waitpid()%20system%20call,options%20argument%2C%20as%20描述%20如下

引发的信号将触发您为该特定信号类型设置的处理程序函数,在示例中为 SIGCHLD。

例子在这里。 https://stackoverflow.com/questions/13792900/signal-and-sigchld-what-does-it-do

正如您在上面的链接中看到的,wait() 不必位于处理程序内部。

那只是等待子进程终止。

所以基本上,没有直接的关系,只是当分叉的子进程死亡时会生成一个 SIGCHLD 信号,并且 wait() 将等待子进程正确终止。

相关内容