fork()父子进程间信号处理(江湖救急)

为什么在子进程中有死循环(如下图),而程序运行之后子进程中的死循环自动结束了,并且没有对收到的信号做自定义处理(输出:接收到信号2)呢?
图片说明

按理来说,结果不应该是这样么?
图片说明

源代码:

 #include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>

void accept_signal(int sig){
    printf("捕获了信号%d\n",sig);
    return;
}
int main(void)
{
    pid_t pid = fork();
    if(pid < 0){
        perror("fork");
        exit(EXIT_FAILURE);
    }
    else if(pid == 0){
        signal(SIGINT,accept_signal);
        while(1);
    }
    printf("父进程给子进程%d发送信号2\n",pid);
    kill(pid,SIGINT);
    return 0;
}

已经解决:在父进程执行kill之前sleep(1);以确保子进程先运行,否则父进程先运行,信号发送是有问题的。

你在程序中不是已经把子进程kill掉了吗?
kill(pid,SIGINT)

把这句注释掉
命令行里输kill -2

另外问问题时,最好附上源码

父进程只是给子进程发送了一个信号2(SIGINT),而子进程对于信号2的处理,并不会按照默认的方式进行(默认是结束进程,子进程死循环被终止),应该按照我们自定义的信号处理函数进行处理(输出:捕获了信号2)。

代码有问题。改成这样:
if(pid < 0){
perror("fork");
exit(EXIT_FAILURE);
}
else if(pid == 0){
signal(SIGINT,accept_signal);
while(1);
}else if(pid > 0)
{
printf("父进程给子进程%d发送信号2\n",pid);
kill(pid,SIGINT);
}
return 0;

一共有两个问题:
第一个问题,如【征途开始的】的描述。fork() 之后的代码,父子进程共享,那就会造成两次信号发送:一次是父进程给子进程发送,一次是自己子进程给自己发送。这大概率不是楼主原本的意图。
第二个问题,子进程的 signal() 对 SIGINT 的配置,可能在父进程的 kill() 调用之后发生。

解决方案:
解决第一个问题,按 【征途开始的】的回复,用 pid 区分父子进程代码逻辑。
解决第二个问题,让父进程在 kill() 调用之前睡眠一会儿,让子进程完成自己的 signal() 调用。另外一种方案是在 fork() 调动之前,调用 signal() 对 SIGINT 进程配置,因为子进程会继承父进程的 sighand ,所以相当于同时配置了父子进程。解决第二个问题的具体代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>


volatile int stop = 0;


void signal_handler(int sig)
{
    printf("%d(): signal catch: %d\n", getpid(), sig);
}

int main(void)
{
    pid_t pid/* = fork()*/;
    int ret;

    printf("parent is %d()\n", getpid());

    // 解决第二个问题的方案2:
    // 让子进程会继承父进程的 sighand,这样父进程无需 sleep()
    signal(SIGINT, signal_handler);  

    pid = fork();
    
    if (pid < 0) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) { // 子进程代码
        // 子进程收不到 SIGINT 的原因是,是父进程发送信号的时候,子进程的 SIGINT 尚未配置。
        // 在这里配置子进程的 SIGINT 可能来不及:父进程发信号时,子进程的 signal() 调用可能没有完成好。
        //signal(SIGINT, signal_handler); //  解决第二个问题的方案1代码片段
        
        while (1)
            ;
    } else { // 父进程代码
        printf("parent: send SIGINT to children %d\n", pid);
        //sleep(5);  //  解决第二个问题的方案1代码片段
        kill(pid, SIGINT);
    }

    return 0;
}