2015-09-27 13 views
17

Poniżej znajduje się przykład funkcji wideł w akcji. Poniżej znajduje się również wynik. Moje główne pytanie związane z widelcem to jak zmieniają się wartości. Więc pid1,2 i 3 zaczynają się od 0 i zmieniają się, gdy pojawiają się widły. Czy dzieje się tak dlatego, że za każdym razem, gdy widelec się dzieje, wartości są kopiowane do dziecka, a określona wartość zmienia się w rodzicu? Zasadniczo jak zmieniają się wartości za pomocą funkcji fork?Funkcja widełek() w C

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

int main() { 
    pid_t pid1, pid2, pid3; 
    pid1=0, pid2=0, pid3=0; 
    pid1= fork(); /* A */ 
    if(pid1==0){ 
     pid2=fork(); /* B */ 
     pid3=fork(); /* C */ 
    } else { 
     pid3=fork(); /* D */ 
     if(pid3==0) { 
      pid2=fork(); /* E */ 
     } 
     if((pid1 == 0)&&(pid2 == 0)) 
      printf("Level 1\n"); 
     if(pid1 !=0) 
      printf("Level 2\n"); 
     if(pid2 !=0) 
      printf("Level 3\n"); 
     if(pid3 !=0) 
      printf("Level 4\n"); 
     return 0; 
    } 
} 

To jest egzekucja.

----A----D--------- (pid1!=0, pid2==0(as initialized), pid3!=0, print "Level 2" and "Level 4") 
    | | 
    | +----E---- (pid1!=0, pid2!=0, pid3==0, print "Level 2" and "Level 3") 
    |   | 
    |   +---- (pid1!=0, pid2==0, pid3==0, print "Level 2") 
    | 
    +----B----C---- (pid1==0, pid2!=0, pid3!=0, print nothing) 
     | | 
     | +---- (pid1==0, pid2==0, pid3==0, print nothing) 
     | 
     +----C---- (pid1==0, pid2==0, pid3!=0, print nothing) 
       | 
       +---- (pid1==0, pid2==0, pid3==0, print nothing) 

Idealnie poniżej jest to, jak chciałbym to wyjaśnić, ponieważ ma to dla mnie sens. * Tutaj znajduje się moje główne zamieszanie. Kiedy dziecko rozwidla się na przykład pid1 = fork();, który tworzy proces ze wszystkimi wartościami rodzica, ale czy przekazuje dalej wartość, powiedzmy powiedzmy 1 do pid1 rodziców? Oznacza to, że dziecko miałoby pid 1 = 0, pid2 = 0 i pid3 = 0, a rodzic następnie jako pid1 = 2, a pid2 i 3 równe 0? enter image description here

+2

widelec() tworzy nowy proces, który pobiera kopię danych niepełnych, jak to było przed fork(). Również wywołanie fork() może mieć trzy wyniki, nie tylko 2 lub 1 (kod robi) Trzy Wyniki są następujące: <0 oznacza błąd = 0 oznacza, dziecko,> 0 oznacza rodzica. Kod powinien zawsze sprawdzać wszystkie trzy wyniki. TO ZNACZY. to: 'pid2 = fork();/* B */ pid3 = fork();/* C */"jest złą praktyką kodowania, ponieważ nie wiadomo, który proces wytworzył" C "(faktycznie będzie 2 z procesów" C ") Podobne rozważania istnieją dla procesu" E " – user3629249

+0

dzieci" B "i" C " nigdy nie dochodzi do instrukcji printf() z powodu wcześniejszej instrukcji "if". Tylko "A", "D" i "E" docierają do instrukcji printf(). – user3629249

+0

youtube.com/watch?v=WcsZvdlLkPw w tym procesie nadrzędnym ma wartość nadpisana przez identyfikator procesu childs jest to poprawne? – Plisken

Odpowiedz

6
int a = fork(); 

Tworzy duplikat procesowego "klon?", Która dzieli stos wykonania. Różnica między rodzicem a dzieckiem jest wartością zwracaną przez funkcję.

Dziecko otrzymało 0, a rodzic otrzymał nowy pid.

Za każdym razem kopiowane są adresy i wartości zmiennych stosu. Wykonanie jest kontynuowane w punkcie, w którym już się znajduje w kodzie.

Przy każdym fork modyfikowana jest tylko jedna wartość - wartość zwracana z fork.

+0

Więc mówisz, że dziecko otrzymuje wartości rodzica, ale przekazuje dowolną wartość rodzicowi, na przykład "1", a to zmienia wartość rodziców? – Plisken

+0

@plisken, wartość jest identyfikatorem procesu dla zwróconego dziecka. W systemie operacyjnym tworzy nową kopię pamięci dla procesu - wszystkie uchwyty plików, biblioteki i przydzielona pamięć są dokładnie takie same. System operacyjny ustawia następnie wartość zwracaną przez funkcję fork na nowy pid, ponieważ rodzic i dziecko otrzymują wartość zwracaną równą 0. Funkcja fork jest prymitywna. Nie można go zapisać w C/C++, chyba że jesteś systemem operacyjnym. Wymyślanie pseudokodu nie miałoby sensu. – mksteve

+0

youtube.com/watch?v=WcsZvdlLkPw w tym procesie macierzystym ma wartość nadpisane przez Childs identyfikator procesu jest to prawidłowe? – Plisken

2

Pierwszy link do jakiejś dokumentacji fork()

http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html

PID jest dostarczane przez jądro. Za każdym razem, gdy jądro utworzy nowy proces, zwiększy to wewnętrzny licznik pid i przypisze nowy proces temu nowemu unikatowemu pidowi, a także upewni się, że nie ma duplikatów. Gdy pid osiągnie pewną dużą liczbę, zawinie się i zacznie od nowa.

Więc nigdy nie wiesz, jaki pid dostaniesz z fork(), tylko że rodzic zachowa unikalny pid i że widelec upewni się, że proces potomny będzie miał nowy unikalny pid. Jest to określone w dokumentacji powyżej.

Kontynuując czytanie dokumentacji zobaczysz, że fork() zwraca 0 dla procesu potomnego, a nowy unikalny pid dziecka zostanie zwrócony rodzicowi. Jeśli dziecko chce wiedzieć, że jest to nowy pid, będziesz musiał o to zapytać za pomocą funkcji getpid().

pid_t pid = fork() 
if(pid == 0) { 
    printf("this is a child: my new unique pid is %d\n", getpid()); 
} else { 
    printf("this is the parent: my pid is %d and I have a child with pid %d \n", getpid(), pid); 
} 

i poniżej niektóre komentarze inline na kodzie

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

int main() { 
    pid_t pid1, pid2, pid3; 
    pid1=0, pid2=0, pid3=0; 
    pid1= fork(); /* A */ 
    if(pid1 == 0){ 
     /* This is child A */ 
     pid2=fork(); /* B */ 
     pid3=fork(); /* C */ 
    } else { 
     /* This is parent A */ 
     /* Child B and C will never reach this code */ 
     pid3=fork(); /* D */ 
     if(pid3==0) { 
      /* This is child D fork'ed from parent A */ 
      pid2=fork(); /* E */ 
     } 
     if((pid1 == 0)&&(pid2 == 0)) { 
      /* pid1 will never be 0 here so this is dead code */ 
      printf("Level 1\n"); 
     } 
     if(pid1 !=0) { 
      /* This is always true for both parent and child E */ 
      printf("Level 2\n"); 
     } 
     if(pid2 !=0) { 
      /* This is parent E (same as parent A) */ 
      printf("Level 3\n"); 
     } 
     if(pid3 !=0) { 
      /* This is parent D (same as parent A) */ 
      printf("Level 4\n"); 
     } 
    } 
    return 0; 
} 
+0

Rozumiem to, robię. Ale to patrzeć https://www.youtube.com/watch?v=WcsZvdlLkPw Widelec przekazuje wartości do rodzica, przypuszczalnie nowym identyfikatorem procesu. Czy to jest poprawne? – Plisken

+0

Tak, to prawda, fork() powie rodzicowi, co pid nowe dziecko ma i oświadczyłem to.Zapoznaj się także z dokumentacją pod linkiem dostępnym pod sekcją "WARTOŚĆ ZWRACANA" – leakim

+0

Przeczytałem, doceniam to bardzo, bardzo pomocne. Ale to moje ostatnie pytanie. Gdy wartość rodziców zostanie zmieniona za pomocą identyfikatora procesu potomnego, dlaczego konieczna jest zmiana innych procesów, jak ma to miejsce w filmie wideo. – Plisken

19

wywołania systemowego fork() służy do tworzenia procesów. Nie przyjmuje argumentów i zwraca identyfikator procesu. Celem fork() jest utworzenie nowego procesu, który staje się procesem podrzędnym osoby dzwoniącej. Po utworzeniu nowego procesu potomnego oba procesy wykonają następną instrukcję po wywołaniu systemowym fork(). Dlatego musimy odróżnić rodzica od dziecka.Można to zrobić, testując zwróconą wartość widelca()

Widelec to wywołanie systemowe i nie należy go traktować jako normalnej funkcji C. Kiedy fork() występuje , skutecznie tworzysz dwa nowe procesy z ich własną przestrzenią adresową. Zmienna, która jest inicjowana przed wywołaniem fork(), zachowuje te same wartości w przestrzeni adresowej. Jednak wartości modyfikowany w przestrzeni adresowej zarówno procesu pozostają nienaruszone w innym procesie z których jedna jest dominująca, a druga jest dziecko. Więc jeśli

pid=fork(); 

Jeśli w kolejnych bloków kodu sprawdzając wartość pid.Both procesy przebiegają na całej długości kodu. Jak więc je rozróżnić. Ponownie Widelec to wywołanie systemowe i tutaj jest różnica. W nowo utworzonym pliku potomnym proces pid przechowuje 0 podczas gdy w procesie nadrzędnym zapisuje wartość dodatnią. Wartość ujemna wewnątrz pid wskazuje błąd widelca.

Kiedy testujemy wartość pid , aby stwierdzić, czy jest ona równa zeru lub większa od niej, skutecznie dowiadujemy się, czy jesteśmy w procesie potomnym czy procesie nadrzędnym.

Read more about Fork

+0

Pytanie, które zadano, dotyczyło tego filmu wideo. https://www.youtube.com/watch?v=WcsZvdlLkPw Dlaczego zmienia wartość w rodzicu? – Plisken

+0

Widelec to wywołanie systemowe. Jak tylko go nazwiesz. Twój proces jest duplikowany. W procesie potomnym pid jest ustawiony na zero, aw procesie nadrzędnym pid ma wartość dodatnią. Teraz pozostała część kodu to to samo dla obu procesów (wykonujemy ten sam kod). Tak więc, aby rozróżnić procesy, w których używamy wartości pid, która jak wspomniano wcześniej jest oddzielna dla dziecka i rodzica –

+0

youtube.com/watch?v=WcsZvdlLkPw w tym proces nadrzędny ma wartość nadpisaną przez identyfikator procesu potomnego jest to poprawne? – Plisken