SIGINT 被多个进程忽略

SIGINT ignored by multiple processes

我想创建三个进程,它们会打印一些东西,直到我按下 ctrl+c。下面你可以看到我的尝试,但是当尝试停止程序时没有任何反应。当只有一个 child 被分叉时,效果很好。哪里可能有问题?提前致谢。

     void my_handler(int s){
          printf("Caught signal %d, I am dying\n",s);
       exit(1);
     }

     void doChild(int count){
     fprintf(stdout,"Child %d with pid: %d\n",count, getpid());
    }


     int main(int argc, char **argv){

     int count = 0;
     pid_t pid;
     struct sigaction sigIntHandler;
     sigIntHandler.sa_handler = my_handler;
     sigemptyset(&sigIntHandler.sa_mask);
     sigIntHandler.sa_flags = 0;
     sigaction(SIGINT, &sigIntHandler, NULL);
     fprintf(stdout, "Ahoj svjete!\n");

     for(;count < 3;count++){
            pid = fork();
    switch(pid){
             case -1:
                    perror("Fork :(");
                     exit(EXIT_FAILURE);

             case 0:
                     while(1){
                            doChild(count);
                    }
       }
    }

     exit(EXIT_SUCCESS);
    }

在此循环中:

for(;count < 3;count++){
    pid = fork();
}

你将创建总共 8 个进程,因为你正在执行 fork() 3 次,即 1. 调用 fork() 给你 1* 2=2 个进程,第二次调用 fork() 给你 2*2=4 个进程,第三次调用 fork() 给你 4*2=8 个进程。

此外,您设置信号处理程序的方式会将信号发送到整个 process group (e.g. parent and children). If this is not what you want, you should look at setpgid() and setsid() 函数,以使每个子进程的信号单独工作。

编辑:

这是您的代码的修改版本,其中包含我添加的一些内容,可帮助您了解正在发生的事情。您还可以在 Chris Dodds 的回答中找到更多关于代码中发生的事情的解释。发送一个信号现在会杀死所有的子进程和父进程,但这段代码只是一个例子,让你了解它是如何工作的(正如我所说,你应该在这里使用进程组)。

void my_handler(int s){
    printf("Caught signal %d, I am dying, my PID=%d\n",s, (int)getpid());
    exit(1);
}

void doChild(int count){
    fprintf(stdout,"Child %d with pid: %d\n",count, getpid());
}

int main(int argc, char **argv){
    int count = 0;
    int status;
    pid_t pid;

    for(;count < 2;count++){
        pid = fork();
    }

    printf("My PID=%d\n", (int)getpid());
    fprintf(stdout, "Ahoj svjete!\n");

    switch(pid){
        case -1:
            perror("Fork :(");
            exit(EXIT_FAILURE);
        case 0:
            signal(SIGINT, my_handler);
            while(1){
                doChild(count);
            }
        default:
            printf("Parent\n");
            sigignore(SIGINT);
            wait(&status);
    }

    printf("Process %d ended life.\n", (int)getpid());
    exit(EXIT_SUCCESS);
}

正如 REACHUS 指出的那样,您得到 8 个进程,而不是 3 个。此外,开关会测试每个进程中 last 分支调用的结果,因此其中 4 个进程会立即退出,而其他 4 个留在 doChild 循环中 运行。

现在因为 top-level 进程(执行第一个 fork 的初始进程)是退出的进程之一(它的 fork 调用所有 return children,从不为 0),shell 再次接管,这意味着当您点击 ctrl-C 时,它会转到 shell 而不是到你的分叉 children。那些 children 永远不会看到 SIGINT(除非你用 kill 明确地将它发送给他们),所以永远不要退出。