在原始程序中,先调用kill(pid,SIGUSR1);,然后在父进程和子进程中调用pause();,先调用pause(),然后调用kill(getppid(),SIGUSR1);其输出如下
在更改后的程序中,如果我将kill(getppid(),SIGUSR1);替换为pause();,则子进程中的输出完全不同。我将输出粘贴到代码下面。
有人能给我解释一下为什么输出会改变吗?
**********************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发布于 2020-12-01 04:31:02
如果进程在为其设置信号处理程序之前接收到SIGUSR1 (并且没有忽略或保留它),则该进程将被终止。(有关详细信息。参见信号man page)。
您的代码(两个版本)都有几个竞争条件。
在第一版中:
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设置一个信号处理程序。
很可能(但不一定总是这样),当父进程处于休眠状态(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,而这几乎肯定会在父进程处于睡眠状态时发生(1)。由于父进程尚未为SIGUSR1设置处理程序,因此信号将终止它。然后,外壳程序打印出用户定义的信号1,这是SIGUSR1信号的长名称。
如果在分支之前为SIGUSR1设置一个信号处理程序,事情会运行得更好。这样,父进程和子进程都将准备好处理信号。
https://stackoverflow.com/questions/65066861
复制相似问题