简体   繁体   English

Linux 信号:孩子没有收到

[英]Linux Signal : Child not receiving

my code is a simple c code where have two processes first one the parents sends signals and print out what it send and the other is the child that receives the signals and print what it received the output of my code is PARENT: sending SIGHUP PARENT: sending SIGINT PARENT: sending SIGQUIT it should be PARENT: sending SIGHUP child received SIGHUP etc...我的代码是一个简单的 c 代码,其中有两个进程,第一个是父母发送信号并打印出它发送的内容,另一个是接收信号并打印它接收到的内容的子进程发送 SIGINT PARENT:发送 SIGQUIT 它应该是 PARENT:发送 SIGHUP 孩子收到 SIGHUP 等...

 // C program to implement sighup(), sigint()
    // and sigquit() signal functions
    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <unistd.h>

    
    // function declaration
    void sighup(int);
    void sigint(int);
    void sigquit(int );
    void sigsegv(int );
    
    // driver code
    int main()
    {
      int pid;
    
      /* get child process */
      if ((pid = fork()) < 0) {
        perror("fork");
        exit(1);
      }
    
      if (pid == 0) { /* child */
        signal(SIGHUP, sighup);
        signal(SIGINT, sigint);
        signal(SIGQUIT, sigquit);
                    signal(SIGSEGV, sigsegv);
        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);
      }
return  0 ;
    }
    
    // sighup() function definition
    void sighup(int signo)
    
    {
      signal(SIGHUP, sighup); /* reset signal */
      printf("CHILD: 1 [sighub]\n");
    }
    
    // sigint() function definition
    void sigint(int signo)
    
    {
      signal(SIGINT, sigint); /* reset signal */
      printf("CHILD: 2 [sigint]\n");
    }
    // sigsegv() function definition
    void sigsegv(int signo)
    
    {
      signal(SIGSEGV, sigsegv); /* reset signal */
      printf("CHILD: 11 [sigsegv]\n");
    }
    
    // sigquit() function definition
    void sigquit(int signo)
    {
    signal(SIGINT, sigquit); /* reset signal */
      printf("3 [sigquit]\n");
      
    }

Probably the first signal is sent before the child has initialized it's signal handling.可能在孩子初始化它的信号处理之前发送第一个信号。 At least I could reproduce the behaviour by adding sleep(2);至少我可以通过添加sleep(2); directly after if (pid == 0) { .直接在if (pid == 0) {之后。

Try adding a sleep() in the parent process before you start sending signals在开始发送信号之前尝试在父进程中添加sleep()

You have several "issues" with the logic of the code (apart from the use of the non async-signal-safe functions).您对代码的逻辑有几个“问题”(除了使用非异步信号安全功能)。

  1. There is no guarantee which process will start working after the fork() .不能保证哪个进程会在fork()之后开始工作。 This depends on the kernel and on the system.这取决于 kernel 和系统。 Linux kernel allows you to make this a deterministic by setting a value in /proc/sys/kernel/sched_child_runs_first , where if value is 0 (default) the parent runs first, and if value is non-zero the child runs first. Linux kernel 允许您通过在/proc/sys/kernel/sched_child_runs_first中设置一个值来使其具有确定性,其中如果值为 0(默认值),则父级首先运行,如果值为非零,则子级首先运行。 Nevertheless, it's not a good practice to depend on this switch for the synchronisation, since on multiprocessor environments, both can run at the same time if we have available CPUs.然而,依赖此开关进行同步并不是一个好习惯,因为在多处理器环境中,如果我们有可用的 CPU,两者可以同时运行。

  2. The processes can be pre-empted at any given moment, either due to the use of system calls, or due to the cpu time.由于使用系统调用或由于 cpu 时间,进程可以在任何给定时刻被抢占。 Therefore, there is no guarantee that the child had set all the signal handlers before the parent had issued the signals, so some of the signals are lost (actually on my tests I got cases where all signals ware lost, once sleep was removed).因此,不能保证孩子在父母发出信号之前已经设置了所有的信号处理程序,所以一些信号会丢失(实际上在我的测试中,一旦睡眠被移除,我得到了所有信号都丢失的情况)。

  3. For the same reason as 2, there is no guarantee that the child got the signal before parent sends the new signal.出于与 2 相同的原因,不能保证孩子在父母发送新信号之前得到信号。

To solve the problem and guarantee the order of execution, you need to create a synchronisation barrier(s).为了解决问题并保证执行顺序,您需要创建一个同步屏障。 Here is example based on IPC pipes that assures the synchronisation.这是基于确保同步的 IPC 管道的示例。 In the example, the parent waits for the child to set-up the signals, and than, for each signal it sends, it waits for the child to confirm that the signal was received.在示例中,父母等待孩子设置信号,然后,对于它发送的每个信号,它都等待孩子确认信号已被接收。

// C program to implement sighup(), sigint()
// and sigquit() signal functions
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>


// function declaration
void sighup(int);
void sigint(int);
void sigquit(int );
void sigsegv(int );

int fd[2]; // communication pipe

// driver code
int main()
{
    int pid;

    if (pipe(fd)==-1)
    {
        fprintf(stderr, "Pipe Failed" );
        exit(1);
    }

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

    if (pid == 0) { /* child */
        close(fd[0]); // Close reading end
        printf("Preparing the signals");
        signal(SIGHUP, sighup);
        printf(".");
        signal(SIGINT, sigint);
        printf(".");
        signal(SIGQUIT, sigquit);
        printf(".");
        signal(SIGSEGV, sigsegv);
        printf(".Signals ready\n");
        write(fd[1],"ready\0", 6);
        for (;;)
            ; /* loop for ever */
    }

    else /* parent */
    { /* pid hold id of child */
        char readb[1024];
        readb[1023] = 0; //Safty stop

        close(fd[1]); // Close writting end
        printf("Waiting for child to finish\n");
        read(fd[0], readb, 1023);
        printf("Child sends %s", readb);

        printf("\nPARENT: sending SIGHUP\n\n");
        kill(pid, SIGHUP);
        read(fd[0], readb, 1023);
        printf("%s\n", readb);

        printf("\nPARENT: sending SIGINT\n\n");
        kill(pid, SIGINT);
        read(fd[0], readb, 1023);
        printf("%s\n", readb);

        printf("\nPARENT: sending SIGQUIT\n\n");
        kill(pid, SIGQUIT);
        read(fd[0], readb, 1023);
        printf("%s\n", readb);

        close(fd[0]);
    }
    return  0 ;
}

// sighup() function definition
void sighup(int signo)
{
    signal(SIGHUP, sighup); /* reset signal */
    write(fd[1],"CHILD: 1 [sighub]\0",18);
}

// sigint() function definition
void sigint(int signo)

{
    signal(SIGINT, sigint); /* reset signal */
    write(fd[1],"CHILD: 2 [sigint]\0",18);
}
// sigsegv() function definition
void sigsegv(int signo)
{
    signal(SIGSEGV, sigsegv); /* reset signal */
    write(fd[1],"CHILD: 11 [sigsegv]\0",20);
}

// sigquit() function definition
void sigquit(int signo)
{
    signal(SIGINT, sigquit); /* reset signal */
    write(fd[1],"CHILD: 3 [sigquit]\0",19);
}

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

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