为什么我的信号处理程序执行两次?
我学习在Linux中进程间通信,使用kill()将信号发送到熟睡的孩子process.Here是我的程序:为什么我的信号处理程序执行两次?
8 void func(void);
9 int main(void){
10 int i, j;
11 pid_t status, retpid;
12 signal(17,func);
13 if(i = fork()){
14 printf("Parent:signal 17 will be sent to child!\n");
15 kill(i, 17);
16 wait(0);
17 printf("child process terminated\n");
18 }
19 else{
20 sleep(10);
21 printf("Child: A signal from my parent is received!\n");
22 exit(0);
23 }
24 }
25 void func(void)
26 {
27 printf("the signal has been sent!\n");
28 }
使用GCC编译,程序产生异常结果,其中FUNC( )执行两次:
./test4.out
Parent:signal 17 will be sent to child!
the signal has been sent!
Child: A signal from my parent is received!
the signal has been sent!
child process terminated
我分析的结果,然后删除以下两个行:
16 wait(0);
17 printf("child process terminated\n");
和结果b ecame正常,用func()只调用一次。看起来罪魁祸首是wait()函数,但为什么它会调用一个信号处理程序?
后校正(最)在贴代码中的错误的..
结果是以下代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
void func(int);
int main(void)
{
pid_t i;
//pid_t status;
//pid_t retpid;
signal(17,func);
if((i = fork()))
{
printf("the fork'd child pid:%d\n", i);
printf("Parent:signal 17 will be sent to child!\n");
kill(i, 17);
wait(NULL);
printf("child process terminated\n");
}
else
{
sleep(10);
printf("Child: pid:%d\n", getpid());
exit(0);
}
}
void func(int theSignal)
{
if(17 == theSignal)
{
fprintf(stdout, "the 17 signal has been processed by %d!\n", getpid());
}
else
{
fprintf(stdout, "the %d signal is processed\n", theSignal);
}
}
并且输出是:
the fork'd child pid:4845
Parent:signal 17 will be sent to child!
the 17 signal has been processed by 4845!
Child: pid:4845
the 17 signal has been processed by 4844!
child process terminated
其中明确显示父母和孩子都处理信号
编辑:
然而,当一个独特SIGUSR2值在下面的代码用作:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
void func(int);
#define MY_SIGNAL (31)
int main(void)
{
pid_t i;
//pid_t status;
//pid_t retpid;
signal(17,func);
signal(31,func);
if((i = fork()))
{
printf("the fork'd child pid:%d\n", i);
printf("Parent:signal %d will be sent to child!\n", MY_SIGNAL);
kill(i, MY_SIGNAL);
wait(NULL);
printf("child process terminated\n");
}
else
{
sleep(10);
printf("Child: pid:%d\n", getpid());
exit(0);
}
}
void func(int theSignal)
{
if(MY_SIGNAL == theSignal)
{
printf("the %d signal has been processed by %d!\n", MY_SIGNAL, getpid());
}
else
{
printf("the %d signal is processed\n", theSignal);
}
}
则输出是:
the fork'd child pid:5099
Parent:signal 31 will be sent to child!
the 31 signal has been processed by 5099!
Child: pid:5099
the 17 signal is processed
child process terminated
这清楚地显示了子处理的信号31(SIGUSR2)和父处理信号17(SIGCHLD)
这仍然存在从信号处理程序调用非信号安全函数的错误。 –
我确实说过我更正了发布代码中错误的“大部分”。我的答案的目的不是指示/演示如何编写信号处理程序,而是为了说明为什么信号处理程序不止一次执行 – user3629249
注意:父接收信号的原因是SIGCHLD的值也为17这意味着价值不是唯一的。如果OP使用31,SIGUSER2,那么它将是唯一的。我编辑了答案来展示这种关系 – user3629249
您正在向子进程发送信号17,因此其处理程序按预期调用。信号17是SIGCHLD
。当子进程死亡时,SIGCHLD
被发送给父进程。父母的处理程序在孩子退出时被调用。这个信号不是来自父母;它来自操作系统,通知父母孩子的死亡。
**可能**当父进程关闭时,它正在等待进程收割者的KILL信号...?一个过程完成后,它不会真的死去。它一直持续到“raper”(无论是所有者还是负责收割僵尸进程的系统进程)都已完成......它可能是收割者信号表明它已完成。 – Myst
'printf'不是一个信号安全函数,不应该在信号处理程序中调用。可能的解释是它导致了未定义的行为(例如,两次刷新粗壮的缓冲区 - 一次在信号处理程序中,一次在进程退出时)。 – kaylum
请发布文本代码,不要与前缀行号码。我们不能只抓取发布的代码并将其粘贴到我们的编辑器中,而无需进行大量逐行编辑。不要使用制表符缩进,因为每个文字处理器/编辑器都有为各个偏好设置的制表位/制表符宽度。即使修复了行号问题,发布的代码也不会编译。它似乎缺少所需的'#include'语句 – user3629249