首页 > 解决方案 > 我想知道这个程序输出背后的原因

问题描述

在原始程序中 kill(pid, SIGUSR1); 首先调用 pause(); 在父进程中和在子进程中 pause(); 先调用后调用 kill(getppid(), SIGUSR1); 它的输出如下

如果我替换 kill(getppid(), SIGUSR1); 在更改的程序中 暂停();在子进程中输出完全不同我已将输出粘贴到代码下方。

有人可以解释一下为什么输出会改变吗

**********************ORIGINAL PROGRAM***********************************
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

void action(int dummy){  
     sleep(1); 
     printf("Switching\n");
}

int main(int argc, char *argv[]){  
    pid_t pid;

    if((pid=fork())>0){//parent  
        sleep(1);
        while(1){
            printf("Parent is running\n");  
            kill(pid, SIGUSR1);  
            signal(SIGUSR1, action);  
            pause();
        }
    }
    else  //child code
        while(1){//child  
            signal(SIGUSR1, action);  
            pause();
            printf("Child is running\n");  
            kill(getppid(), SIGUSR1);
    }
}


//OUTPUT OF THIS PROGRAM
Parent is running
Switching
Child is running
Switching
Parent is running
Switching
Child is running
Switching
Parent is running
Switching
Child is running
Switching
Parent is running
Switching
Child is running
Switching
Parent is running
Switching
Child is running






*********************CHANGED PROGRAM************************

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

void action(int dummy){  
     sleep(1); 
     printf("Switching\n");
}

int main(int argc, char *argv[]){  
    pid_t pid;

    if((pid=fork())>0){//parent  
        sleep(1);
        while(1){
            printf("Parent is running\n");  
            kill(pid, SIGUSR1);  
            signal(SIGUSR1, action);  
            pause();
        }
    }
    else  //child code
        while(1){//child  
            signal(SIGUSR1, action);  
            kill(getppid(), SIGUSR1);
            printf("Child is running\n");  
             pause();
    }
}





//OUTPUT OF THIS PROGRAM
//Child is running
//User defined signal 1


标签: csignalscomputer-sciencekill-processpause

解决方案


如果一个进程在为其设置信号处理程序之前接收到 SIGUSR1(并且没有忽略或持有它),则该进程将被终止。(有关详细信息。请参阅信号手册页)。

您的代码(两个版本)有几个竞争条件。

在第一个版本中:

if((pid=fork())>0){//parent  
    sleep(1);
    while(1){
        printf("Parent is running\n");  
        kill(pid, SIGUSR1);  
        signal(SIGUSR1, action);  
        pause();
    }
}
else  //child code
    while(1){//child  
        signal(SIGUSR1, action);  
        pause();
        printf("Child is running\n");  
        kill(getppid(), SIGUSR1);
}

孩子将等待 SIGUSR1。

大约在同一时间,父母会睡觉,然后将 SIGUSR1 发送给孩子。

接收到信号后,子进程会执行几个 printfs,然后将 SIGUSR1 发送给父进程。

大约在同一时间,父级将为 SIGUSR1 设置一个信号处理程序。

很可能(但不一定总是如此)孩子将在父母执行 sleep(1) 时设置信号处理程序;从父母发送给孩子的信号将被捕获而不是导致孩子被终止。

很可能(但不一定总是如此)当孩子完成它的两个 printfs 时,父母已经设置了信号处理程序;从孩子发送给父母的信号将被捕获而不是导致父母被终止。

但是,由于存在竞争条件,时间上的微小变化可能会导致事情中断。

在第二个版本中:

if((pid=fork())>0){//parent  
    sleep(1);
    while(1){
        printf("Parent is running\n");  
        kill(pid, SIGUSR1);  
        signal(SIGUSR1, action);  
        pause();
    }
}
else  //child code
    while(1){//child  
        signal(SIGUSR1, action);  
        kill(getppid(), SIGUSR1);
        printf("Child is running\n");  
        pause();
}

子进程在它分叉后立即将 SIGUSR1 发送给父进程,这几乎肯定会在父进程处于 sleep(1) 中间时发生。由于父级尚未为 SIGUSR1 设置处理程序,因此信号将终止它。然后 shell 打印出User defined signal 1,这是 SIGUSR1 信号的长名称。

如果您在分叉之前为 SIGUSR1 设置信号处理程序,事情会更好。这样,父母和孩子都准备好处理信号。


推荐阅读