2010-12-16 12 views
0

Ich versuche zu verstehen, wie fork()/Linux Kernel mit globalen Variablen befasst.Forking, Signale und wie sie mit globalen Variablen interagieren C

Gegeben Code:

#include<signal.h> 
#include<unistd.h> 
#include<stdio.h> 
#include<errno.h> 
#include <sys/types.h> 

pid_t pid; 
int counter = 2; 
void handler1(int sig) 
{ 
counter = counter - 1; 
printf("%d", counter); 
exit(0); 
} 
int main() 
{ 
    signal(SIGUSR1, handler1); //Install Handler 
    printf("%d", counter);  //Print Parent global variable 
    pid = fork();    //Fork(), child pid = 0, parent's pid = positive int. 
    if (pid == 0)    //Parent skips this, child goes into infinite loop 
    { 
     while(1) {}; // simulate doing some work 
    } 
    kill(pid, SIGUSR1);  //While child is the loop, parents calls to terminate the child. 
           //Child will stop the infinite loop, and will not proceed any 
           //Will it call handler1 ??? 

    wait(NULL);    //Wait for child to be ripped 
           //Will it call handler1 second time ??? 
    counter = counter + 1;  //This will surely increment global variable 
    printf("%d", counter); 
    exit(0); 
} 

Der Ausgang ist 2123 Wie Unix/Linux-Kernel mit globalen Variablen nach fork() und Signal-Handler genannt werden ??? Werden sie zwischen dem Kind & Eltern geteilt?

Ein weiteres Problem, das ich mit diesem Code habe, ist, wie kill() & wait() wird mit globalen Variablen umgehen und welche Menge werden sie verwenden - Eltern oder Kinder? Und werden sie Signalhandler anrufen?

Danke!

+0

Wer ist der perverse Lehrer, der das Semester mit 'fork' beendet hat? –

+0

einfach den Code in Google-Suche stecken, wird es in den alten Prüfungen sofort – newprint

Antwort

2

Nach fork() wird der gesamte Prozess, einschließlich aller globalen Variablen, dupliziert. Das Kind ist eine genaue Replik des Mutter, mit der Ausnahme, dass es eine andere PID hat, einen anderen Elternteil und fork() zurück 0.

Ein Signal-Handler in dem Kind des Kindes unabhängige Kopie der globalen Variablen verwendet werden.

Der Grund, warum Sie 2 zweimal gedruckt sehen, ist, dass Sie die Standardausgabe nach dem Drucken nicht gelöscht haben. Dies ist, was passiert:

  • counter bis 2.
  • Mutter Prozess gleich ausführt printf("%d", counter);, die "2" in den stdout Ausgabepuffer versetzt, aber tut nicht bündig es. Es erscheint noch keine Ausgabe.
  • fork() wird aufgerufen, die den Prozess dupliziert. Es gibt jetzt zwei Kopien der counter Variable, und beide sind auf 2 gesetzt. Es gibt auch zwei Instanzen des stdout Ausgabepuffers, die beide die Zeichenfolge "2" enthalten. Es erscheint noch keine Ausgabe.
  • Das übergeordnete Element sendet SIGUSR1 an das untergeordnete Element und blockiert unter wait().
  • Das Kind führt handler1(), die das Kind Kopie counter auf 1 dekrementiert, und setzt in den "1"stdout Ausgangspuffer des Kindes (das "21" enthält jetzt).
  • Das Kind führt exit(0), die als Nebeneffekt stdout spült. Die Ausgabe "21" erscheint jetzt, vom Kind geschrieben, und das Kind wird beendet.
  • wait() kehrt im übergeordneten Prozess zurück. Der Elternteil erhöht seine Kopie von counter auf 3 und druckt dann "3" in seinen stdout Ausgabepuffer (der jetzt "23" enthält).
  • Das übergeordnete Element führt exit(0) aus, was als Nebeneffekt stdout löscht. Die Ausgabe "23" wird jetzt angezeigt, und das übergeordnete Element wird beendet.

Wenn Sie fflush(stdout); vor dem fork() setzen, wird die 2 nur einmal gedruckt werden, und der Ausgang "213" sein wird. Es empfiehlt sich, alle gepufferten Ausgabeströme vor dem Aufruf von fork() zu leeren.

5

Das Kind erhält eine unabhängige Kopie der globalen Variablen. Die zwei Kopien sind nicht geteilt.

3

fork erstellt eine Kopie des Prozesses in seinem aktuellen Zustand. Es werden nur gemeinsam genutzte Speicherressourcen (anonyme freigegebene Zuordnungen, freigegebene Zuordnungen, gemeinsam genutzte sysv-Speicherblöcke und gemeinsam genutzte POSIX-Blöcke) freigegeben.

Sie sollten sich darüber im Klaren sein, dass der neue Prozess zwar eine eigene Kopie der Dateideskriptortabelle hat, diese Dateideskriptoren jedoch auf die gleichen "geöffneten Dateibeschreibungen" im Kernel verweisen. Sie teilen unter anderem eine aktuelle Suchposition.

Weitere Informationen finden Sie unter:

http://www.opengroup.org/onlinepubs/9699919799/functions/fork.html

+0

Das Codesegment wird geteilt und möglicherweise das konstante Datensegment? –

+0

Dateideskriptoren werden gemeinsam verwendet (da es sich um eine Ressource handelt, die vom Betriebssystem verwaltet wird, enthält Ihre Anwendung nur ein Handle). Dateideskriptoren umfassen 'Dateisystemdateien' und 'Sockets'. –

+0

Dateideskriptoren werden nicht geteilt; Sie werden kopiert, aber sie beziehen sich auf die gleichen zugrunde liegenden "offenen Dateibeschreibungen" (dies ist die Sprache, die POSIX verwendet), ähnlich wie wenn Sie sie mit "dup" erstellt haben. –