2016-11-05 11 views
0

は私が子供process.Here睡眠に信号を送信するためにキル()を使用して、Linuxでのプロセス間通信を勉強することは私のプログラムです:gccでコンパイルさ私のシグナルハンドラがなぜ2回実行されるのですか?

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 } 

、プログラムが異常な結果を生じ、これFUNC(中)2回実行:

./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 

私は結果を分析し、その後、次の2行を削除:

16     wait(0); 
17     printf("child process terminated\n"); 

そして結果bをfunc()は一度だけ呼び出されます。原因はwait()関数だと思われますが、なぜシグナルハンドラを呼び出すのですか?投稿コードのエラー(ほとんど)を補正した後

+0

**おそらく**親プロセスがプロセスリーパーからのKILL信号を待っているときに...?プロセスが終了すると、実際には終了しません。それは "ラッパー"(ゾンビプロセスを受け持っている所有者かシステムプロセスのいずれか)が終了するまで続きます...それが完了したことを通知する刈り手かもしれません。 – Myst

+3

'printf'はシグナルセーフな関数ではなく、シグナルハンドラで呼び出されるべきではありません。可能性のある説明は、未定義の振る舞いを引き起こしているということです(例えば、シグナルハンドラで1回、プロセスが終了したときに1回、スタウトバッファを2回フラッシュします)。 – 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 

親と子の両方が信号を処理することを示します。

EDIT:

一意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); 
    } 
} 

、出力は次のとおり明確子処理された信号31(SIGUSR2)とを示し

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 

親プロセス信号17(SIGCHLD)

+1

シグナルハンドラから非シグナルセーフな関数を呼び出すというエラーがまだあります。 –

+0

私は、投稿されたコードの「MOST」を修正したと言いました。私の答えの目的は、シグナルハンドラの記述方法を指示する方法ではなく、シグナルハンドラが複数回実行される理由を示すことです。 – user3629249

+0

注:親がシグナルを受け取る理由は、SIGCHLDも17これは、値が一意ではないことを意味します。もしOPがSIGUSER2のために31を使用するならば、それは一意であろう。私はこの関係を示す答えを編集した – user3629249

2

信号17を子プロセスに送信しているので、そのハンドラが期待通りに呼び出されます。

シグナル17はSIGCHLDです。 SIGCHLDは、子プロセスが終了すると親プロセスに送信されます。子プロセスが終了すると、親のハンドラが呼び出されます。この信号は親から来ていません。それはOSから来て、子供の死の親に通知する。

関連する問題