Dlaczego domyślny mechanizm tworzenia procesów jest rozwidlony?


46

Wywołanie systemowe UNIX do tworzenia procesów, fork (), tworzy proces potomny poprzez skopiowanie procesu macierzystego. Rozumiem, że prawie zawsze następuje wywołanie exec () w celu zastąpienia przestrzeni pamięci procesu potomnego (w tym segmentu tekstowego). Kopiowanie przestrzeni pamięci rodzica w fork () zawsze wydawało mi się marnotrawstwem (chociaż zdaję sobie sprawę, że marnotrawstwo można zminimalizować poprzez kopiowanie segmentów pamięci przy zapisie, więc kopiowane są tylko wskaźniki). W każdym razie, czy ktoś wie, dlaczego takie podejście do powielania jest wymagane do tworzenia procesów?


3
Zauważ, że fork(2)strona podręcznika pod Linuksem mówi: Under Linux, fork() is implemented using copy-on-write pages, so the only penalty that it incurs is the time and memory required to duplicate the parent's page tables, and to create a unique task structure for the child. Wyobrażam sobie (ale nie jestem pewien), że tak jest w przypadku innych współczesnych smaków uniksowych.
larsks

4
Oryginalny, uniksowy PDP-11, naprawdę skopiował wszystkie bajty rozwidlonego procesu: ale miał tylko 64 KB wykonywalnego i co najwyżej 64 KB danych, więc nie był to ogromny ciężar, nawet w 1975 roku. domyślam się, że KAŻDY system uniksowy i podobny od około 1990 roku ma segmenty tekstowe do kopiowania i zapisywania, więc nie jestem nawet pewien, dlaczego książki i artykuły propagują „problem z wydajnością za pomocą widelca”.
Bruce Ediger,

Obecnie rozwidlenie jest implementowane w podobny sposób jak vfork ( openbsd.org/cgi-bin/… ). Jest wydajny, nie martw się.
Aki,

Zauważ również, że istnieje wiele zastosowań, w których nie wykonujesz po rozwidleniu (a przynajmniej nie wykonuje się od razu): pomyśl o potokach i serwerach WWW.
jfg956

Być może sprawa będzie wolna. Ale jak mówi @cjm, spójrz na alternatywną metodę Microsoft wykorzystującą CreateProcess, musieli oni wcześniej wdrożyć wątki (być może jedyną rzeczą, do której prowadzą), ponieważ CreateProcess działa wolno. (Potrzebowali także wątków, ponieważ selectzostały zepsute, ale to już inna historia).
ctrl-alt-delor

Odpowiedzi:


57

Ma to na celu uproszczenie interfejsu. Alternatywą forki execbyłoby coś jak Windows' CreateProcess funkcji. Zauważ, ile CreateProcessma parametrów , a wiele z nich to struktury o jeszcze większej liczbie parametrów. Dzieje się tak, ponieważ wszystko , co możesz chcieć kontrolować nad nowym procesem, musi zostać przekazane CreateProcess. W rzeczywistości CreateProcessnie ma wystarczających parametrów, więc Microsoft musiał dodać CreateProcessAsUser i CreateProcessWithLogonW .

W fork/execmodelu nie potrzebujesz wszystkich tych parametrów. Zamiast tego niektóre atrybuty procesu są zachowywane w poprzek exec. Umożliwia forkto zmianę, a następnie zmianę dowolnych atrybutów procesu (przy użyciu tych samych funkcji, których normalnie używasz), a następnie exec . W Linuksie forknie ma parametrów i execvema tylko 3: program do uruchomienia, wiersz poleceń, aby go podać, i jego środowisko. (Istnieją inne execfunkcje, ale są one tylko opakowaniami execvedostarczonymi przez bibliotekę C w celu uproszczenia typowych przypadków użycia).

Jeśli chcesz, aby rozpocząć proces z innego katalogu bieżącego: fork, chdir, exec.

Jeśli chcesz przekierować stdin / stdout: forkblisko / Otwórz pliki exec.

Jeśli chcesz użytkowników przełączników: fork, setuid, exec.

Wszystkie te rzeczy można łączyć w razie potrzeby. Jeśli ktoś wymyśli nowy rodzaj atrybutu procesu, nie musisz go zmieniać forki exec.

Jak wspomniano w Larsku, większość współczesnych Uniksów używa kopiowania przy zapisie, więc forknie wiąże się to z dużym nakładem pracy .


16
Doskonałe wyjaśnienie. „Ci, którzy nie rozumieją systemu UNIX, skazani są na jego ponowne opracowanie, słabo”. - Henry Spencer
Kyle Jones

1
Dzięki! Czy masz przypadkiem referencję?
Ellen Spertus,

1
@Aki, nope, CreateProcess () dosłownie tworzy nowy proces i buduje go od zera, bez rozwidlania.
psusi

2
Ale czy gdzieś w Uniksie nie może istnieć jakiś odpowiednik CreateProcess ()? W przeciwnym razie, jak powstaje pierwszy proces? W przeciwieństwie do mitologicznego boga stwórcy, pierwszy proces nie może wyrwać się () z nicości. ;-)
Steven poniedziałek

2
@StevenMonday, tak, ale jest w kodzie inicjującym jądra i nie jest dostępny z zewnątrz. Nie potrzebuje wszystkich tych parametrów, ponieważ prawie wszystko jest zakodowane na stałe. Może tworzyć tylko proces o identyfikatorze 1, czyli proces inicjowania. Następnie procesy są tworzone tylko przez rozwidlenie.
cjm

5

Oprócz odpowiedzi cjm specyfikacja Single Unix definiuje funkcję o nazwie vfork(). Ta funkcja działa jak fork, z wyjątkiem tego, że rozwidlony proces ma niezdefiniowane zachowanie, jeśli robi coś innego niż próba wywołania funkcji exec rodzinnej lub wywołania _exit().

Tak więc prawie jedynym zastosowaniem ze zdefiniowanym zachowaniem jest:

pid_t ret = vfork();
if(ret == 0)
{
    exec(...);
    _exit(EXIT_FAILURE); //in case exec failed for any reason.
}

Co więc robi vfork? To jest tanie fork. W implementacjach bez kopiowania przy zapisie wynikowy proces będzie współdzielił przestrzeń pamięci z procesem oryginalnym (stąd niezdefiniowane zachowanie). W implementacjach z kopiowaniem przy zapisie vforkdozwolona jest identyczność fork(), ponieważ implementacje kopiowania przy zapisie są szybkie.

Istnieje również posix_spawnfunkcja opcjonalna (i posix_spawnpfunkcja), która może bezpośrednio utworzyć nowy proces. (Dozwolone jest również ich implementowanie za pomocą wywołania biblioteki przy użyciu forki execoraz podano przykładową implementację).

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.