程序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;
}Bash :
$ cc fork_wait.c -o fork_wait && ./fork_wait
I am your father. (...) You know it to be true !
NOOOOOOOOOOOOOOOOOOOOO!!!! NOOOOOOO!!执行时Bash :
$ pgrep fork_wait
37818
37819
$ kill -9 $(pgrep fork_wait | tail -1)
$ pgrep fork_wait
(nothing)当进程被SIGTERM杀死时,谁会发送SIGCHLD信号?如果我杀了儿子,为什么没有僵尸程序?
发布于 2022-03-09 19:59:59
这是你第一个节目的改编本。它使用默认的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%.4X\n", 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
$您可以分析返回的状态(使用WIFSIGNALED、WIFTERMSIG、WIFEXITED、WEXITSTATUS、WCOREDUMP等),它将显示儿童死亡是因为它收到信号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)
$当我在SA_RESTART Moneterey 12.2.1上省略了macOS标志时,得到的结果如下:
$ 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()循环。你也可以安排它去处理另一个信号,这样你就可以让它醒过来,发现它的孩子已经死了。
https://stackoverflow.com/questions/71414581
复制相似问题