首页
学习
活动
专区
圈层
工具
发布

SIGKILL
EN

Stack Overflow用户
提问于 2022-03-09 18:50:03
回答 1查看 403关注 0票数 1

程序fork_wait.c :

代码语言:javascript
复制
#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 :

代码语言:javascript
复制
$ cc fork_wait.c -o fork_wait && ./fork_wait
I am your father. (...) You know it to be true !
NOOOOOOOOOOOOOOOOOOOOO!!!! NOOOOOOO!!

执行时Bash :

代码语言:javascript
复制
$ pgrep fork_wait
37818
37819

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

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-03-09 19:59:59

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

代码语言:javascript
复制
#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;
}

一个示例运行结果:

代码语言:javascript
复制
$ 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):

代码语言:javascript
复制
#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;
}

制作了一个样本运行:

代码语言:javascript
复制
$ 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标志时,得到的结果如下:

代码语言:javascript
复制
$ forkwait73
63929: I am your father. (...) You know it to be true!
63930: NOOOOOOOOOOOOOOOOOOOOO!!!! NOOOOOOO!!
$

如果没有SA_RESTART,父进程不会报告其子进程的死亡,因为wait()errno == EINTR中失败了。与其设置SA_RESTART,不如将循环修改为:

代码语言:javascript
复制
        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()循环。你也可以安排它去处理另一个信号,这样你就可以让它醒过来,发现它的孩子已经死了。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71414581

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档