2009-11-03 10 views
15

Mam więc tę funkcję, która przesuwa liczbę N procesów podrzędnych. Wygląda jednak na to, że rozwidla się bardziej niż podana. Czy możesz mi powiedzieć, co robię źle? DziękiProblem rozwidlania fork() wiele procesów Unix

void forkChildren(int nChildren){ 
    int i; 
    for(i = 1; i <= nChildren; i++){ 
     pid = fork(); 
     if(pid == 0)   
      printf("I'm a child: %d PID: %d\n",i, getpid()); 
    } 

} 

W głównym wezwanie I:

forkChildren(5); 

Oczekuję następujący wynik:

I'm a child: 1 PID: 2990 
I'm a child: 2 PID: 2991 
I'm a child: 3 PID: 2992 
I'm a child: 4 PID: 2993 
I'm a child: 5 PID: 2994 

Ale zamiast uzyskać następujące:

I'm a child: 1 PID: 2990 
I'm a child: 2 PID: 2991 
I'm a child: 3 PID: 2992 
I'm a child: 4 PID: 2993 
I'm a child: 5 PID: 2994 
[email protected]:~/directory/$ I'm a child: 2 PID: 2999 
I'm a child: 3 PID: 3000 
I'm a child: 3 PID: 3001 
I'm a child: 4 PID: 3002 
I'm a child: 5 PID: 3003 
I'm a child: 5 PID: 3004 
I'm a child: 4 PID: 3005 
I'm a child: 5 PID: 3006 
I'm a child: 4 PID: 3007 
I'm a child: 5 PID: 3008 
I'm a child: 3 PID: 3011 
I'm a child: 4 PID: 3012 
I'm a child: 4 PID: 3010 
I'm a child: 5 PID: 3013 
I'm a child: 5 PID: 3014 
I'm a child: 5 PID: 3015 
I'm a child: 4 PID: 3018 
I'm a child: 5 PID: 3019 
I'm a child: 5 PID: 3020 
I'm a child: 5 PID: 3021 
I'm a child: 5 PID: 3023 
I'm a child: 5 PID: 3025 
I'm a child: 5 PID: 3024 
I'm a child: 4 PID: 3022 
I'm a child: 5 PID: 3026 
I'm a child: 5 PID: 3027 
+2

Widzę teraz. Właśnie wstawiłem wyjście (0); po każdym dziecku wypisuje swoje informacje. – user69514

Odpowiedz

14

Wywołanie fork() wywołuje nowy proces, który rozpoczyna jego wykonywanie w dokładnie tym samym punkcie, gdzie nastąpiło rozwidlenie. Wygląda na to, że fork "zwraca dwa razy".

To, co się dzieje, polega na tym, że twoje wywołanie fork() zwraca dwa razy, więc zarówno proces nadrzędny, jak i podrzędny kontynuują pętlę i tworzą nowe procesy. Każde dziecko (zarówno pierwotnego rodzica, jak i dziecka) następnie przesuwa się ponownie, wielokrotnie podwajając liczbę procesów ...

+0

Niezupełnie podwojenie. Dzieci ciągle się powiększają w pętli, więc każda z drugiej generacji utworzy tylko czworo wnuków, * nie * 5. Jest to jakaś forma silni. Ale, poza tym * mniejszym * nitpick, dobra odpowiedź. – paxdiablo

+0

@paxdiablo: dziecko robi inkrement, ale tylko jego lokalną kopię. Nie ma wpływu na kopię i. Rodzica. –

1

Każdy dziecko pr ocess podnosi i kontynuuje pętlę.

Innymi słowy, dziecko 1 zrodził i kontynuuje iteracji pętli # 2 itp

Gdy proces jest rozwidlony, kopia bieżącego procesu jest, otrzymany proces potomny kontynuuje wykonywanie po widełek() połączenie. Dlatego musisz dbać o kod powrotu w swojej logice.

15

Po zakończeniu procesu, w zasadzie kończy się to na dwóch (prawie) dokładnych kopiach procesu i obu z nich będzie nadal działać.

Co się dzieje, że same dzieci kontynuują pętlę we własnej przestrzeni procesowej (po wydrukowaniu swoich wydruków) oraz jako rodzic robiący to. I w rzeczywistości, ponieważ te dzieci również się rozwidlają, wnuki będą również kontynuować od tego momentu. Jestem pewien, że istnieje formuła pozwalająca na ustalenie, z iloma dziećmi skończysz (prawdopodobnie coś takiego jak N!), Ale nie mam teraz siły, by to rozgryźć. Lepiej użyć następującego rozwiązania.

Sposób na odróżnienie rodzica od dziecka to wartość zwracana z fork.

  • Jeśli wrócisz -1, jesteś rodzicem i nie powiodło się fork.
  • Jeśli odzyskasz zero, jesteś dzieckiem.
  • Jeśli otrzymasz z powrotem numer dodatni, jesteś rodzicem, a ten numer jest dzieckiem PID (aby można było nim manipulować lub nim manipulować).

Oto niektóre kodu testu:

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

void forkChildren (int nChildren) { 
    int i; 
    pid_t pid; 
    for (i = 1; i <= nChildren; i++) { 
     pid = fork(); 
     if (pid == -1) { 
      /* error handling here, if needed */ 
      return; 
     } 
     if (pid == 0) { 
      printf("I am a child: %d PID: %d\n",i, getpid()); 
      sleep (5); 
      return; 
     } 
    } 
} 

int main (int argc, char *argv[]) { 
    if (argc < 2) { 
     forkChildren (2); 
    } else { 
     forkChildren (atoi (argv[1])); 
    } 
    return 0; 
} 

a niektóre wyjście, aby pokazać, co się dzieje:

pax> forktest 5 
I am a child: 1 PID: 4188 
I am a child: 2 PID: 4180 
I am a child: 3 PID: 5396 
I am a child: 4 PID: 4316 
I am a child: 5 PID: 4260 

pax> _ 
+0

Zmieniono, by wyjaśnić. – paxdiablo

+0

Pomagam znajomemu z przydziałem systemu operacyjnego, a powyższa funkcja działa dobrze, niż się wydaje! –

1

W tym ćwiczeniu użyję rekurencji zamiast pętli for. W ten sposób można wywołać wiele razy instrukcję fork(), ale tylko jedną z dwóch kopii procesu. Możesz sprawić, by dziecko zaczęło odradzać inny proces potomny, w ten sposób mając dziadków, pradziadków itd. Lub możesz wywołać fork() po stronie rodzica, mając jednego "ojca" i wiele dzieci. To jest próbka kodu, który implementuje to ostatnie rozwiązanie:

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

int nChildren; 

void myFork(int n); 

int main(int argc, char *argv[]) { 

    // just a check on the number of arguments supplied 
    if (argc < 2) { 
    printf("Usage: forktest <number_of_children>\n"); 
    printf("Example: forktest 5 - spawns 5 children processes\n"); 
    return -1; 
    } 

    nChildren = atoi(argv[1]); 
    // starting the recursion... 
    myFork(nChildren-1); 
    return 0; 
} 

// the recursive function 
void myFork(int n) { 
    pid_t pid; 

    pid = fork(); 

    // the child does nothing but printing a message on screen 
    if (pid == 0) { 
    printf("I am a child: %d PID: %d\n", nChildren-n, getpid()); 
    return; 
    } 

    // if pid != 0, we're in the parent 
    // let's print a message showing that the parent pid is always the same... 
    printf("It's always me (PID %d) spawning a new child (PID %d)\n", getpid(), pid); 
    // ...and wait for the child to terminate. 
    wait(pid); 

    // let's call ourself again, decreasing the counter, until it reaches 0. 
    if (n > 0) { 
    myFork(n-1); 
    } 
} 
Powiązane problemy