Jaka jest różnica między fork () a vfork ()?

13

Chciałbym szczegółowo zrozumieć różnicę między fork () a vfork (). Nie byłem w stanie całkowicie przetrawić strony podręcznika.

Chciałbym również wyjaśnić jeden z moich kolegów komentujących: „ W obecnym systemie Linux nie ma vfork (), nawet jeśli go nazwiesz, wywoła wewnętrznie fork () ”.

Sen
źródło

Odpowiedzi:

24

Strony podręcznika są zwykle krótkimi dokumentami referencyjnymi. Wikipedia to lepsze miejsce, w którym można znaleźć wyjaśnienia pojęciowe.

Fork powiela proces: tworzy proces potomny, który jest prawie identyczny z procesem nadrzędnym (najbardziej oczywistą różnicą jest to, że nowy proces ma inny identyfikator procesu). W szczególności fork (koncepcyjnie) musi skopiować całą pamięć procesu nadrzędnego.

Ponieważ jest to dość kosztowne, vfork został wymyślony do obsługi typowego specjalnego przypadku, w którym kopiowanie nie jest konieczne. Często pierwszą rzeczą, którą robi proces potomny, jest załadowanie nowego obrazu programu, więc dzieje się tak:

if (fork()) {
    # parent process …
} else {
    # child process (with a new copy of the process memory)
    execve("/bin/sh", …);  # discard the process memory
}

Te execveładunki połączeń nowy program wykonywalny, a ta zastępuje proces za kod i dane pamięci przez kod nowego pliku wykonywalnego i świeżej pamięci danych. Tak więc cała utworzona przez nią kopia pamięci forkbyła na nic.

W ten sposób vforkwezwanie zostało wymyślone. Nie tworzy kopii pamięci. Dlatego vforkjest tani, ale trudny w użyciu, ponieważ musisz upewnić się, że nie masz dostępu do żadnego stosu lub sterty procesu w procesie potomnym. Zauważ, że nawet czytanie może stanowić problem, ponieważ proces nadrzędny jest wykonywany. Na przykład ten kod jest uszkodzony (może, ale nie musi działać, w zależności od tego, czy dziecko lub rodzic najpierw otrzyma wycinek czasu):

if (vfork()) {
    # parent process
    cmd = NULL; # modify the only copy of cmd
} else {
    # child process
    execve("/bin/sh", "sh", "-c", cmd, (char*)NULL);  # read the only copy of cmd
}

Od czasu wynalezienia vfork wymyślono lepsze optymalizacje. Większość współczesnych systemów, w tym Linux, wykorzystuje formę kopiowania przy zapisie , w której strony w pamięci procesu nie są kopiowane w momencie forkwywołania, ale później, gdy rodzic lub dziecko po raz pierwszy pisze na stronie. Oznacza to, że każda strona zaczyna się jako udostępniona i pozostaje udostępniona, dopóki którykolwiek z procesów nie zapisze na tej stronie; proces, który pisze, otrzymuje nową stronę fizyczną (z tym samym adresem wirtualnym). Kopiowanie przy zapisie sprawia, że ​​vfork jest w większości bezużyteczny, ponieważ forknie tworzy żadnej kopii w przypadkach, w których vforkbyłby użyteczny.

Linux zachowuje vfork. forkWywołanie systemowe muszą jeszcze zrobić kopię wirtualnym stole pamięci procesu, nawet jeśli nie kopiować rzeczywistą pamięć; vforknawet nie musi tego robić. Poprawa wydajności jest znikoma w większości aplikacji.

Gilles „SO- przestań być zły”
źródło
1
Dzięki za tę genialną odpowiedź. Podczas wykonywania fork () dziecko i tak otrzyma nowy identyfikator procesu i powiązaną z nim Przestrzeń wirtualną, dlaczego więc powinien nadal tworzyć kopię tabeli pamięci wirtualnej procesu? W tej części nie jestem jasny.
Sen
@Sen: forkmusi utworzyć osobne odwzorowanie pamięci wirtualnej, aby kolejne kopie kopiowania przy zapisie wpływały tylko na jeden z dwóch procesów.
Gilles 'SO - przestań być zły'
czy jesteś pewien, że proces nadrzędny jest uruchomiony?
qbolec
2

fork()I vfork()syscalli są różne.

fork()Syscall generuje dwa identyczne procesów z oddzielnej pamięci. vfork()Syscall generuje dwa procesy, które dzielą tę samą pamięć.

Z vfork()rodzicem będzie czekać na zakończenie dziecka. Element nadrzędny dziedziczy po zmiennych współużytkowanych przez program. Tak więc po wywołaniu dziecka wszystkie zmienne zmodyfikowane wewnątrz dziecka będą nadal modyfikowane wewnątrz rodzica.

Aby uzyskać więcej informacji, kliknij tutaj

Yogeesh HT
źródło