如果我是正确的,进程会通过调用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_KILLED
、CLD_DUMPED
、CLD_TRAPPED
或CLD_STOPPED
,CLD_CONTINUED
则si.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
我没有足够的观点来发表评论,但这应该可以回答你的问题。
引发的信号将触发您为该特定信号类型设置的处理程序函数,在示例中为 SIGCHLD。
例子在这里。 https://stackoverflow.com/questions/13792900/signal-and-sigchld-what-does-it-do
正如您在上面的链接中看到的,wait() 不必位于处理程序内部。
那只是等待子进程终止。
所以基本上,没有直接的关系,只是当分叉的子进程死亡时会生成一个 SIGCHLD 信号,并且 wait() 将等待子进程正确终止。