Według Wikipedii (co może być błędne)
Po wydaniu wywołania systemowego fork () tworzona jest kopia wszystkich stron odpowiadających procesowi nadrzędnemu, ładowana przez system operacyjny do osobnego miejsca w pamięci dla procesu potomnego. Ale w niektórych przypadkach nie jest to konieczne. Rozważ przypadek, gdy dziecko wykonuje
exec
wywołanie systemowe ("używane do wykonania dowolnego pliku wykonywalnego z programu C) lub kończy pracę wkrótce pofork()
. Gdy dziecko jest potrzebne tylko do wykonania polecenia dla procesu nadrzędnego, nie ma potrzeby kopiowania stron procesu nadrzędnego, ponieważexec
zastępuje przestrzeń adresową procesu, który ją wywołał, poleceniem do wykonania.W takich przypadkach stosowana jest technika zwana kopiowaniem przy zapisie (COW). Dzięki tej technice, gdy występuje rozwidlenie, strony procesu nadrzędnego nie są kopiowane do procesu potomnego. Zamiast tego strony są współużytkowane przez proces podrzędny i nadrzędny. Ilekroć proces (rodzic lub dziecko) modyfikuje stronę, tworzona jest osobna kopia samej strony dla tego procesu (rodzic lub dziecko), który dokonał modyfikacji. Ten proces będzie wykorzystywał nowo skopiowaną stronę zamiast udostępnionej we wszystkich przyszłych odniesieniach. Drugi proces (ten, który nie zmodyfikował udostępnionej strony) nadal korzysta z oryginalnej kopii strony (która nie jest już udostępniana). Ta technika nazywa się kopiowaniem przy zapisie, ponieważ strona jest kopiowana, gdy jakiś proces do niej zapisuje.
Wygląda na to, że gdy którykolwiek z procesów próbuje zapisać na stronie, nowa kopia strony zostaje przydzielona i przypisana do procesu, który wygenerował błąd strony. Oryginalna strona zostaje następnie oznaczona do zapisu.
Moje pytanie brzmi: co się stanie, jeśli fork()
wywołanie zostanie wywołane wiele razy, zanim którykolwiek z procesów spróbuje napisać na udostępnionej stronie?
pmap -XX PID
lubcat /proc/PID/smap
.Odpowiedzi:
Nic szczególnego się nie dzieje. Wszystkie procesy współużytkują ten sam zestaw stron i każdy otrzymuje swoją prywatną kopię, gdy chce zmodyfikować stronę.
źródło
Zachowanie fork () zależy od tego, czy system * nix ma MMU, czy nie. W systemie innym niż MMU (takim jak wczesne PDP-11) wywołanie systemowe fork () skopiowało całą pamięć rodzica dla każdego dziecka. W systemie * nix opartym na MMU jądro zaznacza wszystkie strony bez stosu jako R / O i dzieli je między rodzicem a dzieckiem. Następnie, gdy którykolwiek proces zapisuje na dowolnej stronie, MMU przechwytuje próbę, jądro przydziela stronę do zapisu i aktualizuje tabele stron MMU, aby wskazywały na stronę, którą można teraz zapisać. To zachowanie kopiowania przy zapisie przyspiesza, ponieważ początkowo tylko prywatny stos musi zostać przydzielony i sklonowany dla każdego procesu potomnego.
Jeśli wykonasz jakiś kod nadrzędny między każdym wywołaniem fork (), wówczas wynikowe procesy podrzędne będą się różnić stronami zmienionymi przez nadrzędny. Z drugiej strony, jeśli rodzic po prostu wyda wiele wywołań fork (), np. W pętli, wówczas procesy potomne będą prawie identyczne. Jeśli używana jest zmienna pętli lokalnej, będzie ona inna w stosie każdego dziecka.
źródło
Gdy system przygotowuje rozwidlenie, zwykle (może to zależeć od implementacji) oznacza również strony jako tylko do odczytu i oznacza proces nadrzędny jako wzorzec tych stron.
Podczas próby zapisu na tych stronach występuje błąd strony i system operacyjny przejmuje kontrolę, kopiując całą listę stron lub tylko te zmienione (ponownie, zależnie od implementacji), więc proces zapisu będzie miał zapisywalną kopię.
Gdy z tego samego rozwidlonych jest wiele procesów, gdy proces „master” zapisuje w pamięci, pozostałe procesy kopiują swoje równoważne strony.
źródło