2016-11-05 129 views
0

我學習在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

回答

0

後校正(最)在貼代碼中的錯誤的..

結果是以下代碼:

#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

2

您正在向子進程發送信號17,因此其處理程序按預期調用。信號17是SIGCHLD。當子進程死亡時,SIGCHLD被髮送給父進程。父母的處理程序在孩子退出時被調用。這個信號不是來自父母;它來自操作系統,通知父母孩子的死亡。

相關問題