简体   繁体   English

从父母发送信号给孩子

[英]sending signal from parent to child

I am using this tutorial from website http://www.code2learn.com/2011/01/signal-program-using-parent-child.html and trying to understand why signal is not recieved by child? 我正在使用http://www.code2learn.com/2011/01/signal-program-using-parent-child.html网站上的这个教程,并试图了解为什么信号没有被孩子收到?

here is the code: 这是代码:

#include <stdio.h>  
#include <signal.h>
#include <stdlib.h>  
void sighup(); /* routines child will call upon sigtrap */  
void sigint();  
void sigquit();  
void main()  
{ int pid;  
    /* get child process */  
    if ((pid = fork()) < 0) {  
        perror("fork");  
        exit(1);  
    }  
    if (pid == 0)  
    { /* child */  
        signal(SIGHUP,sighup); /* set function calls */  
        signal(SIGINT,sigint);  
        signal(SIGQUIT, sigquit);  
        for(;;); /* loop for ever */  
    }  
    else /* parent */  
    { /* pid hold id of child */  
        printf("\nPARENT: sending SIGHUP\n\n");  
        kill(pid,SIGHUP);  
        sleep(3); /* pause for 3 secs */  
        printf("\nPARENT: sending SIGINT\n\n");  
        kill(pid,SIGINT);  
        sleep(3); /* pause for 3 secs */  
        printf("\nPARENT: sending SIGQUIT\n\n");  
        kill(pid,SIGQUIT);  
        sleep(3);  
    }  
}  
void sighup()  
{ signal(SIGHUP,sighup); /* reset signal */  
    printf("CHILD: I have received a SIGHUP\n");  
}  
void sigint()  
{ signal(SIGINT,sigint); /* reset signal */  
    printf("CHILD: I have received a SIGINT\n");  
}  
void sigquit()  
{ printf("My DADDY has Killed me!!!\n");  
    exit(0);  
}  

output: 输出:

在此输入图像描述

It's a race condition. 这是竞争条件。 Your code assumes that the child runs first and is not preempted by the parent until it installed all signal handlers and starts looping forever. 您的代码假定子进程先运行并且不会被父进程抢占,直到它安装所有信号处理程序并开始永远循环。

When that is not the case, the parent may send a signal to the child before the child had the chance to catch the signal. 如果不是这种情况,父母可能会在孩子有机会接收信号之前向孩子发出信号。 As such, the child process is killed, since the default action for SIGHUP , SIGINT and SIGQUIT is to terminate. 因此,子进程被终止,因为SIGHUPSIGINTSIGQUIT的默认操作是终止。

In your specific case, you never see any output from the child. 在您的具体情况下,您永远不会看到孩子的任何输出。 This means that the parent sent SIGHUP to the child, and SIGHUP was delivered before the child changed the default behavior. 这意味着父级已将SIGHUP发送给子级,并且在子级更改默认行为之前已传递SIGHUP So the child was killed. 所以孩子被杀了。

Actually, if you did some error checking on the returning value of kill(2) - which you should - you would see ESRCH in the parent upon trying to send SIGINT and SIGQUIT , because the child is already gone (assuming no other process in the system was started and got assigned the same PID in the meantime). 实际上,如果你对kill(2)的返回值做了一些错误检查 - 你应该 - 你会在尝试发送SIGINTSIGQUIT时看到父进程中的ESRCH ,因为该子进程已经消失(假设没有其他进程)系统启动并同时分配了相同的PID。

So, how do you fix it? 那么,你如何解决它? Either use some form of synchronization to force the child to run first and only let the parent execute after all signal handlers are installed, or set up the signal handlers before forking, and then unset them in the parent. 使用某种形式的同步来强制子进程先运行,只允许父进程在安装所有信号处理程序后执行,或者分叉之前设置信号处理程序,然后在父进程中取消设置它们。 The code below uses the latter approach: 下面的代码使用后一种方法:

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

void sighup(int); /* routines child will call upon sigtrap */
void sigint(int);
void sigquit(int);

int main(void) {

    int pid;

    signal(SIGHUP,sighup); /* set function calls */
    signal(SIGINT,sigint);
    signal(SIGQUIT, sigquit);

    /* get child process */
    if ((pid = fork()) < 0) {
        perror("fork");
        exit(1);
    }

    if (pid == 0) {

        /* child */
        for(;;); /* loop for ever */

    } else {

        signal(SIGHUP, SIG_DFL);
        signal(SIGINT, SIG_DFL);
        signal(SIGQUIT, SIG_DFL);

        /* parent */
        /* pid hold id of child */
        printf("\nPARENT: sending SIGHUP\n\n");
        kill(pid,SIGHUP);
        sleep(3); /* pause for 3 secs */
        printf("\nPARENT: sending SIGINT\n\n");
        kill(pid,SIGINT);
        sleep(3); /* pause for 3 secs */
        printf("\nPARENT: sending SIGQUIT\n\n");
        kill(pid,SIGQUIT);
        sleep(3);
    }

    return 0;
}

void sighup(int signo) {
    signal(SIGHUP,sighup); /* reset signal */
    printf("CHILD: I have received a SIGHUP\n");
}

void sigint(int signo) {
    signal(SIGINT,sigint); /* reset signal */
    printf("CHILD: I have received a SIGINT\n");
}

void sigquit(int signo) {
    printf("My DADDY has Killed me!!!\n");
    exit(0);
}

Also, you shouldn't be using signal(2) : it is unreliable in many ways, and its exact semantics are platform dependent. 此外,您不应该使用signal(2) :它在许多方面都不可靠,其确切的语义依赖于平台。 To ensure maximum portability, you should use sigaction(2) . 为确保最大的可移植性,您应该使用sigaction(2) Refer to the manpages to learn more. 请参阅联机帮助页以了解更多信息。 Here's the same code using sigaction(2) instead: 这是使用sigaction(2)的相同代码:

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

void sighup(int); /* routines child will call upon sigtrap */
void sigint(int);
void sigquit(int);

int main(void) {

    struct sigaction sigact;
    sigact.sa_flags = 0;
    sigemptyset(&sigact.sa_mask);

    sigact.sa_handler = sighup;
    if (sigaction(SIGHUP, &sigact, NULL) < 0) {
        perror("sigaction()");
        exit(1);
    }

    sigact.sa_handler = sigint;
    if (sigaction(SIGINT, &sigact, NULL) < 0) {
        perror("sigaction()");
        exit(1);
    }

    sigact.sa_handler = sigquit;
    if (sigaction(SIGQUIT, &sigact, NULL) < 0) {
        perror("sigaction()");
        exit(1);
    }

    pid_t pid;
    /* get child process */
    if ((pid = fork()) < 0) {
        perror("fork");
        exit(1);
    }

    if (pid == 0) {

        /* child */
        for(;;); /* loop for ever */

    } else {

        sigact.sa_handler = SIG_DFL;
        sigaction(SIGHUP, &sigact, NULL);
        sigaction(SIGINT, &sigact, NULL);
        sigaction(SIGQUIT, &sigact, NULL);

        /* parent */
        /* pid hold id of child */
        printf("\nPARENT: sending SIGHUP\n\n");
        kill(pid,SIGHUP);
        sleep(3); /* pause for 3 secs */
        printf("\nPARENT: sending SIGINT\n\n");
        kill(pid,SIGINT);
        sleep(3); /* pause for 3 secs */
        printf("\nPARENT: sending SIGQUIT\n\n");
        kill(pid,SIGQUIT);
        sleep(3);
    }

    return 0;
}

void sighup(int signo) {
    signal(SIGHUP,sighup); /* reset signal */
    printf("CHILD: I have received a SIGHUP\n");
}

void sigint(int signo) {
    signal(SIGINT,sigint); /* reset signal */
    printf("CHILD: I have received a SIGINT\n");
}

void sigquit(int signo) {
    printf("My DADDY has Killed me!!!\n");
    exit(0);
}

Last, but not least, it is important to mention that you should always compile with -Wall . 最后,但并非最不重要的是,重要的是要提到您应该始终使用-Wall编译。 Your program has some mistakes: 你的程序有一些错误:

  • The return type of main() should be int . main()的返回类型应为int
  • Signal handlers receive the signal number as an argument, please use the right prototype and declaration. 信号处理程序接收信号编号作为参数,请使用正确的原型和声明。
  • fork(2) returns a pid_t , not an int , please use the correct type. fork(2)返回一个pid_t ,而不是一个int ,请使用正确的类型。
  • You need to include unistd.h to get the right prototype for fork(2) . 你需要包含unistd.h来获得fork(2)的正确原型。
  • printf(3) is not async-signal safe and as such you shouldn't call it inside a signal handler. printf(3)不是异步信号安全的,因此你不应该在信号处理程序中调用它。 It's ok in this toy program to see how signals work together, but keep in mind that you should never do it in the real world. 在这个玩具程序中可以看到信号如何协同工作,但请记住,你不应该在现实世界中这样做。 To see a list of async-signal safe functions, as well as the default actions for each signal, see man 7 signal . 要查看异步信号安全功能列表以及每个信号的默认操作,请参阅man 7 signal

Word of advice: stop learning from that website. 建议:停止从该网站学习。 If you want to learn this kind of stuff, read Advanced Programming in the UNIX Environment . 如果您想学习这类内容,请阅读UNIX环境中的高级编程 Go straight to chaper 10 to learn why exactly signal(2) is considered unreliable and obsolescent. 直接进入第10章,了解为什么signal(2)被认为是不可靠和过时的。 It's a big book, but it's well worth investing your time on it. 这是一本很大的书,但值得投入时间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM