2016-11-05 2 views
0

I Inter-Prozess-Kommunikation in Linux lerne, mit kill() Signale senden Kind process.Here zu schlafen ist mein Programm:Warum wird mein Signalhandler zweimal ausgeführt?

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 } 

mit gcc kompiliert, das Programm erzeugt anormales Ergebnis, bei dem func () zweimal ausgeführt:

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

I das Ergebnis analysiert, und dann die beiden folgenden Zeilen gelöscht:

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

und das Ergebnis b wurde normal, mit func() nur einmal aufgerufen. Es scheint, dass der Schuldige die wait() - Funktion ist, aber warum sollte er jemals einen Signal-Handler aufrufen?

+0

** Vielleicht **, wenn der Elternprozess geschlossen wird, wartet er auf ein KILL-Signal vom Prozessmesser ...? Wenn ein Prozess beendet ist, stirbt er nicht wirklich. Es bleibt, bis der "Rapper" (entweder der Besitzer oder der Systemprozess, der für das Ernten von Zombie-Prozessen zuständig ist) fertig ist ... Es könnte der Sensenmann sein, der signalisiert, dass es getan ist. – Myst

+3

'printf' ist keine signalsichere Funktion und sollte nicht in einem Signalhandler aufgerufen werden. Die mögliche Erklärung ist, dass es Undefined Behavior verursacht (z. B. den Stout-Puffer zweimal löschen - einmal im Signal-Handler und einmal, wenn der Prozess beendet wird). – kaylum

+1

bitte Text eingeben, nicht mit vorangestellten Zeilennummern. Wir können den geposteten Code nicht einfach in unsere Editoren einfügen und einfügen, ohne viel Zeile für Zeile bearbeiten zu müssen. Verwenden Sie keine Tabs zum Einrücken, da für jedes Textverarbeitungsprogramm/Editor die Tabstopps/Tabulatoren für die einzelnen Einstellungen festgelegt sind. Auch nach dem Beheben des Zeilennummernproblems kompiliert der gebuchte Code nicht. Es scheint zu fehlen die benötigten '# include' Anweisungen – user3629249

Antwort

0

nach (die meisten) der Fehler in den entsandten Code zu korrigieren ..

Das Ergebnis ist der folgende Code:

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

und der Ausgang ist:

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 

die eindeutig zeigt, dass sowohl das Elternteil als auch das Kind das Signal verarbeiten

EDIT:

Wenn jedoch ein einzigartiger SIGUSR2 Wert wird, wie in der folgenden Kode:

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

dann ist der Ausgang:

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 

das eindeutig das Kind zeigt verarbeitete Signal 31 (SIGUSR2) und die Übergeordnetes verarbeitetes Signal 17 (SIGCHLD)

+1

Dies hat immer noch den Fehler, von einem Signal-Handler eine nicht-signalsichere Funktion aufzurufen. –

+0

Ich habe gesagt, dass ich "MOST" der Fehler im gebuchten Code korrigiert habe. Der Zweck meiner Antwort war nicht zu lehren/zu demonstrieren, wie man einen Signalhandler schreibt, sondern vielmehr, warum der Signalhandler mehr als einmal ausgeführt wird. – user3629249

+0

HINWEIS: Der Grund, warum das Elternsignal ein Signal bekommt, ist, dass SIGCHLD auch einen Wert von 17 hat was bedeutet, dass der Wert nicht eindeutig ist. Wenn das OP 31 für SIGUSER2 verwenden würde, dann wäre es eindeutig. Ich habe die Antwort bearbeitet, um diese Beziehung zu zeigen – user3629249

2

Sie senden Signal 17 an den untergeordneten Prozess, sodass der Handler wie erwartet aufgerufen wird.

Signal 17 ist SIGCHLD. SIGCHLD wird an einen übergeordneten Prozess gesendet, wenn ein untergeordneter Prozess abstirbt. Der Handler des Parents wird aufgerufen, wenn das Kind beendet wird. Dieses Signal kommt nicht vom Elternteil; Es kommt vom Betriebssystem, um die Eltern über den Tod des Kindes zu informieren.

Verwandte Themen