Czy wątki są kopiowane podczas wywoływania fork?

31

Jeśli mam program działający z wątkami i wywołujący fork()system uniksowy, czy wątki są kopiowane? Wiem, że pamięć wirtualna dla bieżącego procesu jest kopiowana 1: 1 do nowego spawnowanego procesu. Wiem, że wątki mają swój własny stos w wirtualnej pamięci procesu. Dlatego przynajmniej stos wątków powinien zostać skopiowany. Nie wiem jednak, czy w wątkach jest coś więcej, co nie znajduje się w pamięci wirtualnej i dlatego NIE jest kopiowane. Jeśli nie, to czy dwa procesy współużytkują wątki, czy są to niezależne kopie?

Jean-Baptiste Yunès
źródło

Odpowiedzi:

29

Nie.

Wątki nie są kopiowane fork(). Specyfikacja POSIX mówi (podkreśl, że należy do mnie):

widelec - utwórz nowy proces

Proces należy utworzyć z jednym wątkiem . Jeśli proces wielowątkowy wywołuje fork (), nowy proces powinien zawierać replikę wywołującego wątku i całą jego przestrzeń adresową, prawdopodobnie obejmującą stany muteksów i inne zasoby. W związku z tym, aby uniknąć błędów, proces potomny może wykonywać operacje bezpieczne dla sygnału asynchronicznego tylko do momentu wywołania jednej z funkcji exec.

Aby obejść ten problem, istnieje pthread_atfork()funkcja pomocy.

Jean-Baptiste Yunès
źródło
7

widelec :

Proces potomny jest tworzony z jednym wątkiem - tym, który wywołał fork (). Cała wirtualna przestrzeń adresowa elementu nadrzędnego jest replikowana w obiekcie podrzędnym, w tym stany muteksów, zmiennych warunkowych i innych obiektów pthreads; użycie pthread_atfork (3) może być pomocne w rozwiązywaniu problemów, które może to powodować.

kaylum
źródło
Ale to wydaje się dziwne: dlaczego stosy dla wątków w procesie wywołującym fork są kopiowane, jeśli rzeczywiste wątki (których nie znam zawierają pamięć inną niż pamięć wirtualna) nie są?
Cóż, dlaczego jest to zupełnie inne pytanie. Nie znam oryginalnych decyzji projektowych, które doprowadziły do ​​tego wdrożenia. Jeśli jesteś zainteresowany, powinieneś zadać to pytanie osobno.
kaylum
@dip, ale stos innych wątków nie jest kopiowany, kto to powiedział?
Jean-Baptiste Yunès
1
@ Jean-BaptisteYunès W systemach uniksowych istnieje struktura reprezentująca pamięć wirtualną dla procesu. To jest ten skopiowany. Nie tylko sterty i bss
6
otrzymujesz całą przestrzeń pamięci - a zatem stosy wszystkich wątków. potrzebujesz tego, ponieważ nie ma ograniczeń co do tego, gdzie wskazują wskaźniki znajdujące się na stosie (lub pamięci statycznej) dostępnej dla pozostałego wątku - mogą
równie
4

From The Open Group bazowej Specyfikacja Numer 7, 2018 wydania za widelec :

Proces należy utworzyć z jednym wątkiem. Jeśli proces wielowątkowy wywołuje fork () , nowy proces powinien zawierać replikę wywołującego wątku i całą jego przestrzeń adresową, prawdopodobnie obejmującą stany muteksów i inne zasoby. W związku z tym, aby uniknąć błędów, proces potomny może wykonywać operacje bezpieczne dla sygnału asynchronicznego tylko do momentu wywołania jednej z funkcji exec .

Gdy aplikacja wywołuje fork () z procedury obsługi sygnału, a dowolna z funkcji obsługi rozwidleń zarejestrowanych przez pthread_atfork () wywołuje funkcję, która nie jest bezpieczna dla sygnału asynchronicznego, zachowanie jest niezdefiniowane.

Ian Abbott
źródło
-2

Początkowo „rozwidlenie” było osiągane poprzez zapisanie zadania na dysku, a następnie, zamiast czytania w innym wątku (co byłoby zrobione, gdyby zamienić zadanie na inny), modyfikując identyfikator zadania obrazu nadal w pamięci i kontynuując z jego wykonaniem (jako nowe zadanie). To była bardzo prosta modyfikacja podstawowego mechanizmu przełączania zadań, w którym tylko jedno zadanie zajmowałoby pamięć RAM jednocześnie.

Oczywiście, gdy zarządzanie pamięcią stało się bardziej skomplikowane, schemat ten został zmodyfikowany w celu dopasowania do nowego środowiska.

Hot Licks
źródło
Ciekawe, dlaczego zostało to odrzucone. Tak właśnie zrobił Unix.
Hot Licks
To ciekawy wgląd, ale gdzie wspomina o wątkach? Nie wygląda mi to na odpowiedź.
wastl