Po rozwidleniu (), gdzie dziecko rozpoczyna wykonywanie?


22

Próbuję nauczyć się programowania w systemie UNIX i napotkałem pytanie dotyczące fork (). Rozumiem, że fork () tworzy identyczny proces aktualnie uruchomionego procesu, ale od czego się zaczyna? Na przykład, jeśli mam kod

int main (int argc, char **argv)
{
    int retval;
    printf ("This is most definitely the parent process\n");
    fflush (stdout);
    retval = fork ();
    printf ("Which process printed this?\n");

    return (EXIT_SUCCESS);
}

Dane wyjściowe to:

Jest to zdecydowanie proces nadrzędny.
Który proces to wydrukował?
Który proces to wydrukował?

Myślałem, że fork()tworzy ten sam proces, więc początkowo w tym programie fork()wywołanie będzie rekurencyjnie wywoływane na zawsze. Wydaje mi się, że nowy proces utworzony od fork()zaczyna się po fork()połączeniu?

Jeśli dodam następujący kod, aby rozróżnić proces nadrzędny i podrzędny,

if (child_pid = fork ()) printf ("This is the parent, child pid is %d\n", child_pid);
else printf ("This is the child, pid is %d\n",getpid ());

gdzie po wywołaniu fork () proces potomny rozpoczyna wykonywanie?


5
man forkz pewnością odpowie na twoje pytanie, btw
alex

Odpowiedzi:


23

Nowy proces zostanie utworzony w ramach fork()połączenia i rozpocznie się od powrotu z niego, podobnie jak rodzic. Zwracana wartość (z której zapisałeś retval) fork()to:

  • 0 w procesie potomnym
  • PID dziecka w procesie nadrzędnym
  • -1 u rodzica, jeśli wystąpiła awaria (oczywiście nie ma dziecka)

Twój kod testowy działa poprawnie; przechowuje wartości zwracanej z fork()w child_pidi zastosowania ifw celu sprawdzenia, czy jest to 0 lub nie (choć nie sprawdza błędu)


13

Myślałem, że fork () tworzy ten sam proces, więc początkowo w tym programie wywołanie fork () będzie rekurencyjnie wywoływane na zawsze. Wydaje mi się, że nowy proces utworzony za pomocą fork () rozpoczyna się po wywołaniu fork ()?

Tak. Policzmy linie:

int main (int argc, char **argv)
{
    int retval;                                               /* 1 */
    printf ("This is most definitely the parent process\n");  /* 2 */
    fflush (stdout);                                          /* 3 */
    retval = fork ();                                         /* 4 */
    printf ("Which process printed this?\n");                 /* 5 */
    return (EXIT_SUCCESS);                                    /* 6 */
}

Wykonanie jest następujące:

caller process     fork()  ...
                          
original program            exec()  2  3  4  5  6
                                               
forked program                                   5  6

... co dokładnie wyjaśnia otrzymany wynik.

Jeśli chcesz wiedzieć, jak oryginalny i rozwidlony program może zachowywać się inaczej, ponieważ koniecznie mają ten sam kod, zobacz odpowiedź Michała Mrożka.


Zauważ, że 1 nie jest tak naprawdę instrukcją. Zauważ też, że programy oryginalne i rozwidlone nie działają w tym samym czasie - jedno z nich będzie musiało poczekać, aż drugi przyniesie / zostanie zablokowane.
badp

1
W systemach wielordzeniowych / wieloprocesorowych oba programy mogą faktycznie działać jednocześnie.
jlliagre

@jilliagre W systemach wielordzeniowych naprawdę chodzi o wielowątkowość. Jeśli chodzi o systemy z wieloma procesorami, nie wiem, czy tak jest w praktyce, czy nie . Nie jestem ekspertem w tej dziedzinie - i wydaje się to tak mało prawdopodobnym scenariuszem. Jeśli zgodzimy się, że system operacyjny może uruchamiać wiele procesów w tym samym czasie (to jak miałby obsługiwać współbieżność?), Do czasu, gdy oryginalny program uruchomi instrukcję 4 na CPU, inne procesory i tak prawdopodobnie będą zajęte innymi procesami.
badp

Powiedziałbym, że jest to bardzo prawdopodobny scenariusz, szczególnie, że istnieje bazowe wywołanie systemowe z pewną liczbą operacji we / wy w kroku 5. Zajęcie wszystkich procesorów nie jest tak naprawdę częstą sytuacją, ponieważ procesor rzadko stanowi wąskie gardło w obecnych maszynach. Wygląda na to, że mylisz wielowątkowość i wielordzeniowy procesor.
jlliagre

8
Czy mogę po prostu powiedzieć, że te ukośne strzałki są fantastyczne .
JBirch

0

Prawdziwym rozwiązaniem tego jest

switch (fork()) {
    case -1 :
        fprintf (stderr, "fork failed (%s)\n", strerror(errno));
        break;
    case 0 :  // child process comes here
        break;
    default : // parent process
        break;
}

// all continue here

-1

niezależnie od kodu zaraz po fork(), jest on kopiowany do procesu potomnego i nie mieszają procesu nadrzędnego i potomnego, są to dwie różne jednostki, które mają to samo (zduplikowane, niepodzielone) środowisko.

Teraz zobacz swoje wyniki ...

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.