Jakie wątki ogólnie się dzielą?

20

To jest ogólne pytanie. A jeśli ktoś chce sprecyzować tę implementację, wolę rzeczy związane z Uniksem. Ale najpierw trzeba znać następujące problemy w ogólności:

Czytam, że pojedynczy proces może mieć wiele wątków. Wiele wątków tego samego procesu dzieli się między nimi. Chcę wiedzieć, co dzielą, a co nie. Biorąc pod uwagę proces składa się z przestrzeni adresowej, stosu, stosu, zmiennych globalnych, kodu, danych, zasobów systemu operacyjnego, które z nich są współużytkowane przez wątki? Mam następujące domysły:

  1. Zmienne globalne - przeczytałem zmienną globalną akcji wątku. Również podczas programowania w Javie i C # zrobiłem wątki do dzielenia zmiennych na poziomie klasy. Uważam więc, że wątki dzielą zmienne globalne (choć nie jestem pewien, czy pojęcia w językach programowania wysokiego poziomu przekładają się na fakty dotyczące niskiego poziomu systemu operacyjnego).

  2. Sterta - Ponieważ zmienna globalna jest przechowywana w stercie, sterta jest współużytkowana przez wątki.

  3. Stos - Ponieważ każdy wątek może mieć swoją własną sekwencję / kod wykonania, musi mieć swój własny stos, na którym mógłby wypychać / wyrzucać zawartość licznika programu (gdy powiedzą wywołania funkcji i zwroty). Tak więc wątki tego samego procesu nie dzielą stosu.

Teraz nie jestem pewien co do dzielenia się następującymi rzeczami

  1. Przestrzeń adresowa - Nie jestem pewien, co dokładnie się liczy w przestrzeni adresowej. Ale myślę, że przestrzeń adresowa jest zwykle używana w kontekście procesów, a nie wątków. A ponieważ wszystkie wątki tego samego procesu znajdują się w tej samej przestrzeni adresowej co proces nadrzędny, mówi się, że wątki dzielą przestrzeń adresową. (Ale czy utrzymują inny stos w tej samej przestrzeni adresowej?)

  2. Zasoby systemu operacyjnego - Myślę, że może to być bardzo specyficzne dla implementacji. Na przykład proces nadrzędny może selektywnie przekazać uchwyt tego samego pliku niektórym wątkom, a nie wszystkim. Czy też się mylę, a zasoby systemu operacyjnego oznaczają coś innego niż pliki?

  3. Kod - Wątki mogą mieć inny kod, więc udostępnianie kodu nie zawsze ma miejsce.

  4. Dane - niepewny, co należy uwzględnić w danych. Ale upewnij się, że zmienne globalne są wspólne dla wątków. I upewnij się, że zmienne lokalne nie są podobnie współużytkowane.

Ogólnie jestem bardzo zdezorientowany z powodu niejasnych warunków, superogólności dokonanych w książkach dotyczących systemów operacyjnych oraz szczegółowych informacji na temat dodatkowych wdrożeń dostępnych online. Staram się więc znaleźć odpowiedź, która może mnie zadowolić.

Maha
źródło

Odpowiedzi:

13

Zasadniczo każdy wątek ma własne rejestry (w tym własny licznik programów), własny wskaźnik stosu i własny stos. Cała reszta jest dzielona między wątkami współużytkującymi proces.

W szczególności powszechnie uważa się, że proces składa się z zestawu wątków współużytkujących przestrzeń adresową, stertę, dane statyczne i segmenty kodu oraz deskryptory plików * .

Przestrzeń adresowa jest po prostu mapowaniem adresów logicznych na określone elementy pamięci fizycznej. Kiedy więc mówimy, że wszystkie wątki w procesie mają tę samą przestrzeń adresową, mamy na myśli, że podczas uzyskiwania dostępu do zmiennej foow zasięgu globalnym wszystkie wątki zobaczą tę samą zmienną. Podobnie, wątki mogą działać w innym punkcie kodu w dowolnym momencie, ale wszystkie mogą wywoływać funkcję globalną bar(), która będzie odpowiadać tej samej funkcji dla każdego wątku w procesie.

Większość współczesnych systemów operacyjnych dodała pojęcie lokalnej pamięci wątków , które są zmiennymi o zasięgu globalnym, które nie są współużytkowane. Typowym przykładem użycia tego jest zmienna errno. Jest to jedna zmienna o zasięgu globalnym, ale w większości nowoczesnych systemów operacyjnych każdy wątek otrzymuje własną kopię lokalną, więc błąd w wywołaniu biblioteki w jednym wątku nie wpłynie na zachowanie innych wątków.

* Istnieje pewien dodatkowy stan procesu współużytkowany przez wszystkie wątki w procesie, takie jak identyfikator procesu, obsługa sygnału i blokady plików. Aby uzyskać pełną listę stanu procesu współużytkowanego przez wątki, należy zapoznać się z dokumentacją dotyczącą konkretnej implementacji wątków. Na przykład strona man pthreads .

Wędrująca logika
źródło
4

Wątki pojawiają się w dwóch perspektywach: systemy operacyjne i języki programowania. W obu przypadkach istnieje pewna zmienność atrybutów wątku.

Minimalna definicja wątku polega na tym, że to, co dzieje się w sekwencji, jedna po drugiej.

W typowym modelu wykonania maszyny każdy wątek ma własny zestaw rejestrów ogólnego przeznaczenia i własny licznik programów. Jeśli urządzenie określa konkretny rejestr jako wskaźnik stosu, dla każdego wątku jest jedna kopia.

Z punktu widzenia systemu operacyjnego, minimum systemu operacyjnego do obsługi wątków zapewnia sposób przełączania się między nimi. Może się to zdarzyć albo automatycznie ( wyprzedzająca wielozadaniowość, albo tylko wtedy, gdy wątek jednoznacznie zażąda (wielozadaniowość kooperacyjna; w takim przypadku nici są czasami nazywane włóknami ). Istnieją również modele hybrydowe o wydajności wyprzedzającej i kooperacyjnej, np. Wyprzedzanie między wątkami różnych grup lub zadania, ale wyraźne wyniki między wątkami tej samej grupy / zadania. Przełączanie między wątkami wymaga co najmniej zapisania wartości rejestru starego wątku i przywrócenia wartości rejestru nowego wątku.

W wielozadaniowym systemie operacyjnym zapewniającym izolację między zadaniami (lub procesami można traktować te terminy jako synonimy w kontekście systemu operacyjnego), każde zadanie ma swoje własne zasoby, w szczególności przestrzeń adresową, ale także otwarte pliki, uprawnienia itp. Izolacja ma do dostarczenia przez jądro systemu operacyjnego , jednostkę ponad procesami. Każde zadanie zwykle ma co najmniej jeden wątek - zadanie, które nie wykonuje kodu, nie jest zbyt użyteczne. System operacyjny może, ale nie musi obsługiwać wielu wątków w tym samym zadaniu; na przykład oryginalny uniks nie. Zadanie może nadal uruchamiać wiele wątków, organizując przełączanie między nimi - nie wymaga to żadnych specjalnych uprawnień. Nazywa się to „ wątkami użytkownika”, Szczególnie w kontekście Uniksa. Obecnie większość systemów uniksowych zapewnia wątki jądra, w szczególności dlatego, że jest to jedyny sposób na uruchomienie wielu wątków tego samego procesu na różnych procesorach.

Większość zasobów systemu operacyjnego oprócz czasu obliczeń jest dołączona do zadań, a nie wątków. Niektóre systemy operacyjne (na przykład Linux) wyraźnie ograniczają stosy, w którym to przypadku każdy wątek ma swój własny; ale istnieją systemy operacyjne, w których jądro nie wie nic o stosach, są one tylko częścią stosu. Jądro zazwyczaj również zarządza kontekstem jądra dla każdego wątku, który jest strukturą danych zawierającą informacje o tym, co wątek obecnie robi; pozwala to jądrze obsługiwać wiele wątków zablokowanych w wywołaniu systemowym w tym samym czasie.

Jeśli chodzi o system operacyjny, wątki zadania wykonują ten sam kod, ale znajdują się w różnych pozycjach w tym kodzie (różne wartości liczników programu). Może się zdarzyć lub nie, że pewne części kodu programu są zawsze wykonywane w określonych wątkach, ale zwykle istnieje wspólny kod (np. Funkcje narzędziowe), który można wywołać z dowolnego wątku. Wszystkie wątki widzą te same dane, w przeciwnym razie byłyby uważane za różne zadania; jeśli do niektórych danych można uzyskać dostęp tylko za pomocą określonego wątku, zwykle dotyczy to wyłącznie języka programowania, a nie systemu operacyjnego.

W większości języków programowania pamięć jest dzielona między wątkami tego samego programu. Jest to model współdzielonego programowania pamięci ; jest bardzo popularny, ale także bardzo podatny na błędy, ponieważ programista musi uważać, gdy dostęp do tych samych danych jest możliwy przez wiele wątków, ponieważ mogą wystąpić warunki wyścigu . Zauważ, że nawet zmienne lokalne mogą być współużytkowane między wątkami: „zmienna lokalna” (zwykle) oznacza zmienną, której nazwa jest poprawna tylko podczas jednego wykonania funkcji, ale inny wątek może uzyskać wskaźnik do tej zmiennej i uzyskać do niej dostęp.

Istnieją również języki programowania, w których każdy wątek ma swoją pamięć, a komunikacja między nimi odbywa się poprzez wysyłanie wiadomości kanałami komunikacyjnymi. Jest to model przekazywania współbieżnego programowania. Erlangjest głównym językiem programowania, który koncentruje się na przekazywaniu wiadomości; jego środowisko wykonawcze ma bardzo lekką obsługę wątków i zachęca programy napisane z wieloma krótkotrwałymi wątkami, w przeciwieństwie do większości innych języków programowania, w których tworzenie wątku jest stosunkowo kosztowną operacją, a środowisko wykonawcze nie może obsługiwać bardzo dużych liczba wątków jednocześnie. Sekwencyjny podzbiór Erlanga (część języka, która zachodzi w wątku, w szczególności manipulacja danymi) jest (głównie) czysto funkcjonalny; w ten sposób wątek może wysłać wiadomość do innego wątku zawierającego pewne dane i żaden wątek nie musi się martwić, że dane zostaną zmodyfikowane przez inny wątek podczas jego używania.

Niektóre języki łączą oba modele, oferując lokalną pamięć wątkową, z systemem typów lub bez niego, aby odróżnić lokalną pamięć wątkową od globalnych. Lokalne przechowywanie wątków jest zwykle wygodną funkcją, która pozwala zmiennej nazwie wyznaczyć różne miejsca przechowywania w różnych wątkach.

Niektóre (trudne) działania następcze, które mogą być interesujące dla zrozumienia, jakie są wątki:

  • Jakie minimum musi zrobić jądro, aby obsługiwać wiele wątków?
  • Co trzeba zrobić w środowisku wieloprocesorowym, aby przeprowadzić migrację wątku z jednego procesora do drugiego?
  • Co trzeba zrobić, aby wdrożyć wielowątkowość kooperacyjną ( coroutines ) w swoim ulubionym języku programowania bez wsparcia ze strony systemu operacyjnego i bez korzystania z jego wbudowanej obsługi, jeśli taka istnieje? (Uważaj, że w większości języków programowania brakuje niezbędnych prymitywów do implementacji coroutines w jednym wątku.)
  • Jak mógłby wyglądać język programowania, gdyby miał współbieżność, ale nie miał (jawnej) koncepcji wątków? (Pierwszy przykład: rachunek pi ).
Gilles „SO- przestań być zły”
źródło
To jest najbardziej interesująca rzecz, którą czytałem od miesięcy.
JSON
2

To zależy. Jeśli weźmiesz pod uwagę wątki zdefiniowane np. Przez POSIX (i oferowane przez systemy Unix) lub Windows (nie znając później, będziesz musiał zapytać konkretnie), to daje odpowiedź (zasadniczo jak wyjaśnia odpowiedź @WanderingLogic). Linux ma swój własny pomysł na wątki, wykorzystujący niestandardowe clone(2)wywołanie systemowe. Zapewnia to drobiazgową kontrolę nad tym, co rodzice i dzieci dzielą. Chodzi o to, aby mieć fork(2)i vfork(2)zasadniczo owijać wokół wewnętrznego clone(2), nazywając go specyficznymi flagami, tj. Możesz tworzyć „wątki”, które dzielą się niczym z rodzicem. Szczegółowe informacje można znaleźć na stronie podręcznika, są one dostępne on-line np . Tutaj . Tak, Linux oferuje wątki w stylu POSIX, ale znacznie więcej.

vonbrand
źródło
0

Udostępnianie wątków:

  • Przestrzeń adresowa
  • Sterta
  • Dane statyczne
  • Segmenty kodu
  • Deskryptory plików
  • Zmienne globalne
  • Procesy potomne
  • Oczekujące alarmy
  • Sygnały i procedury obsługi sygnałów
  • Informacje księgowe

Wątki mają swoje własne:

  • Licznik programu
  • Rejestry
  • Stos
  • Stan
ericcurtin
źródło