C语言 SIGCHLD on SIGKILL



程序fork_wait.c:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(){
pid_t a = fork();
if (a != 0) {
int status;
printf("I am your father. (...) You know it to be true !");
wait(&status);
}
else {
printf("NOOOOOOOOOOOOOOOOOOOOO!!!! NOOOOOOO!!");
sleep(2000);
}
return 0;
}

重击:

$ cc fork_wait.c -o fork_wait && ./fork_wait
I am your father. (...) You know it to be true !
NOOOOOOOOOOOOOOOOOOOOO!!!! NOOOOOOO!!

执行时重击:

$ pgrep fork_wait
37818
37819
$ kill -9 $(pgrep fork_wait | tail -1)
$ pgrep fork_wait
(nothing)

当进程被SIGTERM终止时,谁发送SIGCHLD信号?如果我杀了儿子,为什么没有僵尸程序?

这是对您的第一个程序的改编。它使用默认的SIGCHLD信号处理,这意味着当子进程死亡时,信号不会(由内核(传递给父进程(forkwait29.c(:

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void)
{
pid_t a = fork();
if (a != 0)
{
printf("%5d: I am your father. (...) You know it to be true!n", getpid());
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("PID %5d exited with status 0x%.4Xn", corpse, status);
}
else
{
printf("%5d: NOOOOOOOOOOOOOOOOOOOOO!!!! NOOOOOOO!!n", getpid());
sleep(2000);
}
return 0;
}

运行收益率示例:

$ forkwait29
64001: I am your father. (...) You know it to be true!
64002: NOOOOOOOOOOOOOOOOOOOOO!!!! NOOOOOOO!!
PID 64002 exited with status 0x0009
$

您可以分析返回的状态(使用WIFSIGNALEDWIFTERMSIGWIFEXITEDWEXITSTATUSWCOREDUMP等(,它会显示孩子因为接收到信号9 SIGKILL而死亡。正如评论中所指出的,你的父母收集了死去的孩子的过程(防止它成为(持久的(僵尸(并退出。

你可以添加一些像这样的信号处理(forkwait73.c(:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
static volatile sig_atomic_t sig_caught = 0;
static void sig_handler(int signum)
{
sig_caught = signum;
}
int main(void)
{
pid_t a = fork();
if (a != 0)
{
printf("%5d: I am your father. (...) You know it to be true!n", getpid());
struct sigaction sa = { 0 };
sa.sa_handler = sig_handler;
sa.sa_flags = SA_RESTART;
if (sigemptyset(&sa.sa_mask) != 0)
return 1;
sigaction(SIGCHLD, &sa, NULL);
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
{
printf("PID %5d exited with status 0x%.4X (caught = %d)n",
corpse, status, sig_caught);
}
}
else
{
printf("%5d: NOOOOOOOOOOOOOOOOOOOOO!!!! NOOOOOOO!!n", getpid());
sleep(2000);
}
return 0;
}

生产了一个样品:

$ forkwait73
63964: I am your father. (...) You know it to be true!
63965: NOOOOOOOOOOOOOOOOOOOOO!!!! NOOOOOOO!!
PID 63965 exited with status 0x000F (caught = 20)
$

当我在macOS Moneterey 12.2.1上省略SA_RESTART标志时,我得到了这样的结果:

$ forkwait73
63929: I am your father. (...) You know it to be true!
63930: NOOOOOOOOOOOOOOOOOOOOO!!!! NOOOOOOO!!
$

如果没有SA_RESTART,父进程不会报告其子进程的死亡,因为wait()errno == EINTR一起失败。循环可以修改为:,而不是设置SA_RESTART

while ((corpse = wait(&status)) > 0 || errno == EINTR)
{
printf("PID %5d exited with status 0x%.4X (caught = %d)n",
corpse, status, sig_caught);
errno = 0;
}

如果你想看到僵尸进程,你必须安排父进程暂时不要为子进程wait()。你也可以让它休眠,当sleep()调用结束时,它可以继续wait()循环。你也可以安排它处理另一个信号,这样你就可以用信号通知它醒来,发现它的孩子已经死了。

最新更新