Różnice między forkiem a exec

Jakie są różnice między fork i exec?

Author: krpra, 2009-10-31

9 answers

Użycie fork i exec jest przykładem ducha Uniksa, ponieważ zapewnia bardzo prosty sposób uruchamiania nowych procesów.

Wywołanie fork zasadniczo tworzy duplikat bieżącego procesu, identyczny w prawie W każdy sposób. Nie wszystko jest kopiowane (na przykład ograniczenia zasobów w niektórych implementacjach), ale chodzi o to, aby utworzyć jak najbliżej kopii.

Nowy proces (potomek) otrzymuje inny identyfikator procesu (PID) i ma PID starego procesu (parent) jako rodzic PID (PPID). Ponieważ oba procesy uruchamiają teraz dokładnie ten sam kod, mogą stwierdzić, który jest który po kodzie powrotu fork - dziecko otrzymuje 0, rodzic otrzymuje PID dziecka. To wszystko, oczywiście, zakładając, że wywołanie fork działa - jeśli nie, nie zostanie utworzone żadne dziecko, a rodzic otrzyma kod błędu.

Wywołanie exec jest sposobem na zastąpienie całego bieżącego procesu nowym programem. Ładuje program do bieżącej przestrzeni procesowej i uruchamia go z punktu wejścia.

Tak więc, fork i exec są często używane w sekwencji, aby uzyskać nowy program uruchomiony jako potomek bieżącego procesu. Powłoki zwykle robią to za każdym razem, gdy próbujesz uruchomić program taki jak find - widełki powłoki, następnie dziecko ładuje program find do pamięci, ustawiając wszystkie argumenty linii poleceń, standardowe wejścia / Wyjścia itd.

Ale nie muszą być używane razem. Jest to całkowicie dopuszczalne dla samego programu fork Bez execing jeśli, dla przykład, program zawiera zarówno kod rodzica, jak i dziecka (musisz uważać na to, co robisz, każda implementacja może mieć ograniczenia). Było to używane dość często (i nadal jest) w przypadku demonów, które po prostu nasłuchują na porcie TCP i fork ich kopię, aby przetworzyć określone żądanie, podczas gdy rodzic wraca do nasłuchu.

Podobnie programy, które wiedzą, że są gotowe i chcą uruchomić inny program, nie muszą fork, exec a potem wait dla dziecka. Mogą po prostu załaduj dziecko bezpośrednio do przestrzeni procesowej.

Niektóre implementacje Uniksa mają zoptymalizowany fork, który używa tego, co nazywają copy-on-write. Jest to sztuczka polegająca na opóźnieniu kopiowania przestrzeni procesowej w fork, dopóki program nie spróbuje zmienić czegoś w tej przestrzeni. Jest to przydatne dla tych programów, które używają tylko fork, a nie exec, ponieważ nie muszą kopiować całej przestrzeni procesowej.

Jeśli exec czy nazywa się fork (i tak się dzieje najczęściej), który powoduje zapis do przestrzeni procesowej i jest następnie kopiowany dla procesu potomnego.

Zauważ, że istnieje cała rodzina exec połączeń (execl, execle, execve i tak dalej) ale exec w kontekście tutaj oznacza każdy z nich.

Poniższy diagram ilustruje typową operację fork/exec, w której powłoka bash jest używana do wypisania katalogu za pomocą polecenia ls:

+--------+
| pid=7  |
| ppid=4 |
| bash   |
+--------+
    |
    | calls fork
    V
+--------+             +--------+
| pid=7  |    forks    | pid=22 |
| ppid=4 | ----------> | ppid=7 |
| bash   |             | bash   |
+--------+             +--------+
    |                      |
    | waits for pid 22     | calls exec to run ls
    |                      V
    |                  +--------+
    |                  | pid=22 |
    |                  | ppid=7 |
    |                  | ls     |
    V                  +--------+
+--------+                 |
| pid=7  |                 | exits
| ppid=4 | <---------------+
| bash   |
+--------+
    |
    | continues
    V
 380
Author: paxdiablo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-21 22:32:17

fork() dzieli bieżący proces na dwa procesy. Innymi słowy, twój miły, liniowy, łatwy do myślenia program nagle staje się dwoma oddzielnymi programami z jednym kawałkiem kodu: {]}

 int pid = fork();

 if (pid == 0)
 {
     printf("I'm the child");
 }
 else
 {
     printf("I'm the parent, my child is %i", pid);
     // here we can kill the child, but that's not very parently of us
 }
To może cię rozwalić. Teraz masz jeden kawałek kodu z prawie identycznym stanem wykonywanym przez dwa procesy. Proces potomny dziedziczy cały kod i pamięć procesu, który go właśnie utworzył, włączając w to rozpoczęcie od miejsca, w którym zostało przerwane wywołanie fork(). Jedyny różnica polega na kodzie zwrotnym fork() informującym, czy jesteś rodzicem czy dzieckiem. Jeśli jesteś rodzicem, wartością zwracaną jest id dziecka.

exec jest nieco łatwiejsze do uchwycenia, po prostu mówisz exec, Aby wykonać proces za pomocą docelowego pliku wykonywalnego i nie masz dwóch procesów uruchamiających ten sam kod lub dziedziczących ten sam stan. Jak mówi @ Steve Hawkins, exec może być użyty po fork do wykonania w bieżącym procesie docelowego pliku wykonywalnego.

 53
Author: Doug T.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-08 12:29:24

Myślę, że niektóre koncepcje z "Advanced Unix Programming" Marc Rochkind były pomocne w zrozumieniu różnych ról fork()/exec(), specjalnie dla kogoś przyzwyczajonego do okien CreateProcess() model:

A program jest zbiorem instrukcji i danych przechowywanych w zwykłym pliku na dysku. (od 1.1.2 programy, procesy i wątki)

.

Aby uruchomić program, jądro jest najpierw proszone o utworzenie nowego proces , czyli środowisko, w którym program wykonuje (również od 1.1.2 programy, procesy i wątki)

.

Nie jest możliwe zrozumienie wywołań systemowych exec lub fork bez pełnego zrozumienia różnicy między procesem a programem. Jeśli niniejsze warunki są dla Ciebie nowe, możesz wrócić i przejrzeć sekcję 1.1.2. Jeśli jesteś gotowy, aby kontynuować teraz, podsumujemy rozróżnienie w jednym zdaniu: Proces jest wykonaniem środowisko, które składa się z instrukcji, danych użytkownika i segmentów danych systemowych, a także wiele innych zasobów nabytych w czasie wykonywania, podczas gdy program jest plikiem zawierającym instrukcje i dane, które są używane do inicjalizacji instrukcji i segmentów danych użytkownika procesu. (od 5.3 exec wywołania systemowe)

Kiedy zrozumiesz rozróżnienie między programem a procesem, zachowanie fork() i exec() funkcji można podsumować jako:

  • fork() tworzy duplikat bieżącego procesu
  • exec() zastępuje program w bieżącym procesie innym programem
Jest to wersja uproszczona dla manekinów w znacznie bardziej szczegółowej odpowiedzi paxdiablo.]}
 32
Author: Michael Burr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:45

Fork tworzy kopię procesu wywołującego. generalnie wynika ze struktury Tutaj wpisz opis obrazka

int cpid = fork( );

if (cpid = = 0) 
{

  //child code

  exit(0);

}

//parent code

wait(cpid);

// end

(dla procesu potomnego tekst (kod),data, stos jest taki sam jak proces wywołujący) proces potomny wykonuje kod w bloku if.

EXEC zastępuje bieżący proces nowym kodem,danymi,stosem. generalnie wynika ze struktury Tutaj wpisz opis obrazka

int cpid = fork( );

if (cpid = = 0) 
{   
  //child code

  exec(foo);

  exit(0);    
}

//parent code

wait(cpid);

// end

(po wywołaniu Exec jądro Uniksa czyści tekst procesu potomnego, dane, stos i wypełnia tekst/dane związane z procesem foo) tak więc proces potomny jest z different code (foo ' s code {not same as parent})

 31
Author: Sandesh Kobal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-31 20:35:13

Są używane razem, aby utworzyć nowy proces potomny. Po pierwsze, wywołanie fork tworzy kopię bieżącego procesu (proces potomny). Następnie, {[2] } jest wywoływany z wewnątrz procesu potomnego, aby "zastąpić" kopię procesu nadrzędnego nowym procesem.

Proces przebiega mniej więcej tak:

child = fork();  //Fork returns a PID for the parent process, or 0 for the child, or -1 for Fail

if (child < 0) {
    std::cout << "Failed to fork GUI process...Exiting" << std::endl;
    exit (-1);
} else if (child == 0) {       // This is the Child Process
    // Call one of the "exec" functions to create the child process
    execvp (argv[0], const_cast<char**>(argv));
} else {                       // This is the Parent Process
    //Continue executing parent process
}
 7
Author: Steve Hawkins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-31 04:49:33

Fork () tworzy kopię bieżącego procesu, z uruchomieniem w nowym potomku rozpoczynającym się zaraz po wywołaniu fork (). Po fork () są identyczne, z wyjątkiem wartości zwracanej przez funkcję fork (). (RTFM więcej szczegółów.) Te dwa procesy mogą się dalej od siebie różnić, przy czym jeden z nich nie może ingerować w drugi, z wyjątkiem ewentualnych uchwytów plików udostępnionych.

Exec () zastępuje bieżący proces nowym. Nie ma to nic wspólnego z forkiem(), poza tym, że exec () często podąża za fork (), gdy pożądane jest uruchomienie innego procesu potomnego, a nie zastąpienie bieżącego.

 4
Author: Warren Young,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-08 09:04:35

Główna różnica między fork() a exec() jest taka, że

Wywołanie systemowe fork() tworzy klon aktualnie uruchomionego programu. Oryginalny program kontynuuje wykonywanie z następnym wierszem kodu po wywołaniu funkcji fork (). Klon również rozpoczyna wykonywanie w następnej linii kodu. Spójrz na poniższy kod, który dostałem od http://timmurphy.org/2014/04/26/using-fork-in-cc-a-minimum-working-example/

#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
    printf("--beginning of program\n");
    int counter = 0;
    pid_t pid = fork();
    if (pid == 0)
    {
        // child process
        int i = 0;
        for (; i < 5; ++i)
        {
            printf("child process: counter=%d\n", ++counter);
        }
    }
    else if (pid > 0)
    {
        // parent process
        int j = 0;
        for (; j < 5; ++j)
        {
            printf("parent process: counter=%d\n", ++counter);
        }
    }
    else
    {
        // fork failed
        printf("fork() failed!\n");
        return 1;
    }
    printf("--end of program--\n");
    return 0;
}

Ten program deklaruje zmienną licznika, set to zero, before fork() ing. Po wywołaniu fork mamy dwa procesy działające równolegle, oba zwiększają swoją własną wersję licznika. Każdy proces zakończy się i zakończy. Ponieważ procesy przebiegają równolegle, nie wiemy, który zakończy się pierwszy. Uruchomienie tego programu wydrukuje coś podobnego do tego, co pokazano poniżej, chociaż wyniki mogą się różnić w zależności od uruchomienia.

--beginning of program
parent process: counter=1
parent process: counter=2
parent process: counter=3
child process: counter=1
parent process: counter=4
child process: counter=2
parent process: counter=5
child process: counter=3
--end of program--
child process: counter=4
child process: counter=5
--end of program--

Rodzina wywołań systemowych exec() zastępuje aktualnie wykonujący kod przetwarzaj z innym kawałkiem kodu. Proces zachowuje swój PID, ale staje się nowym programem. Na przykład rozważ następujący kod:

#include <stdio.h> 
#include <unistd.h> 
main() {
 char program[80],*args[3];
 int i; 
printf("Ready to exec()...\n"); 
strcpy(program,"date"); 
args[0]="date"; 
args[1]="-u"; 
args[2]=NULL; 
i=execvp(program,args); 
printf("i=%d ... did it work?\n",i); 
} 

Ten program wywołuje funkcję execvp(), aby zastąpić swój kod programem date. Jeśli kod jest przechowywany w pliku o nazwie exec1.c, następnie wykonując go, otrzymujemy następujące wyjście:

Ready to exec()... 
Tue Jul 15 20:17:53 UTC 2008 

Program wyświetla linię-Ready do exec (). . . ‖ i po wywołaniu funkcji execvp () zastępuje jej kod programem date. Uwaga ta linia ... . . czy to działa‖ nie jest wyświetlany, ponieważ w tym momencie kod został zastąpiony. Zamiast tego widzimy wyjście executing-date-u.‖

 4
Author: Abdulhakim Zeinu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-01 18:36:26

Tutaj wpisz opis obrazkafork():

Tworzy kopię uruchomionego procesu. Uruchomiony proces nazywa się procesem macierzystym , a nowo utworzony proces nazywa się procesem potomnym. Sposób rozróżniania tych dwóch wartości polega na spojrzeniu na zwracaną wartość:

  1. fork() zwraca identyfikator procesu (pid) procesu potomnego w rodzicu

  2. fork() zwraca 0 w dziecku.

exec():

Inicjuje nowy proces w ramach procesu. Ładuje nowy program do bieżącego procesu, zastępując istniejący.

fork() + exec():

Podczas uruchamiania nowego programu należy najpierw fork(), utworzyć nowy proces, a następnie exec() (tzn. załadować do pamięci i wykonać) program binarny, który ma być uruchomiony.

int main( void ) 
{
    int pid = fork();
    if ( pid == 0 ) 
    {
        execvp( "find", argv );
    }

    //Put the parent to sleep for 2 sec,let the child finished executing 
    wait( 2 );

    return 0;
}
 1
Author: Yogeesh H T,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-27 07:44:13

Najlepszym przykładem do zrozumienia koncepcji fork() i exec() jest shell,program interpretera poleceń, który użytkownicy zazwyczaj wykonują po zalogowaniu się do systemu.Powłoka interpretuje pierwsze słowo linii poleceń jako polecenie Nazwa

Dla wielu poleceń,powłoka widły i proces dziecka execs polecenie powiązane z nazwą traktujące pozostałe słowa w wierszu poleceń jako parametry polecenia.

Powłoka pozwala na trzy typy komend. Po pierwsze, polecenie może być plik wykonywalny zawierający kod obiektowy wytworzony przez kompilację kodu źródłowego (na przykład programu C). Po drugie, polecenie może być plikiem wykonywalnym, który zawiera sekwencję linii poleceń powłoki. Wreszcie, polecenie może być wewnętrznym poleceniem powłoki.(zamiast pliku wykonywalnego ex->cd,ls itd.)

 0
Author: krpra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-03 06:15:46