为什么我的信号处理程序执行两次?

问题描述:

我学习在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()函数,但为什么它会调用一个信号处理程序?

+0

**可能**当父进程关闭时,它正在等待进程收割者的KILL信号...?一个过程完成后,它不会真的死去。它一直持续到“raper”(无论是所有者还是负责收割僵尸进程的系统进程)都已完成......它可能是收割者信号表明它已完成。 – Myst

+3

'printf'不是一个信号安全函数,不应该在信号处理程序中调用。可能的解释是它导致了未定义的行为(例如,两次刷新粗壮的缓冲区 - 一次在信号处理程序中,一次在进程退出时)。 – kaylum

+1

请发布文本代码,不要与前缀行号码。我们不能只抓取发布的代码并将其粘贴到我们的编辑器中,而无需进行大量逐行编辑。不要使用制表符缩进,因为每个文字处理器/编辑器都有为各个偏好设置的制表位/制表符宽度。即使修复了行号问题,发布的代码也不会编译。它似乎缺少所需的'#include'语句 – user3629249

后校正(最)在贴代码中的错误的..

结果是以下代码:

#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)

+1

这仍然存在从信号处理程序调用非信号安全函数的错误。 –

+0

我确实说过我更正了发布代码中错误的“大部分”。我的答案的目的不是指示/演示如何编写信号处理程序,而是为了说明为什么信号处理程序不止一次执行 – user3629249

+0

注意:父接收信号的原因是SIGCHLD的值也为17这意味着价值不是唯一的。如果OP使用31,SIGUSER2,那么它将是唯一的。我编辑了答案来展示这种关系 – user3629249

您正在向子进程发送信号17,因此其处理程序按预期调用。信号17是SIGCHLD。当子进程死亡时,SIGCHLD被发送给父进程。父母的处理程序在孩子退出时被调用。这个信号不是来自父母;它来自操作系统,通知父母孩子的死亡。