Różnice między forkiem a exec
Jakie są różnice między fork
i exec
?
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 exec
ing 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
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.
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
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
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
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})
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
}
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.
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.‖
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
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ść:
-
fork()
zwraca identyfikator procesu (pid) procesu potomnego w rodzicu 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;
}
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.)
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