Jakie zasoby są współdzielone między wątkami?


264

Niedawno zadano mi pytanie w wywiadzie, jaka jest różnica między procesem a wątkiem. Naprawdę nie znałem odpowiedzi. Myślałem przez chwilę i udzieliłem bardzo dziwnej odpowiedzi.

Wątki dzielą tę samą pamięć, procesy nie. Po udzieleniu odpowiedzi ankieter uśmiechnął się do mnie złośliwie i zwrócił się do mnie z następującymi pytaniami:

P: Czy znasz segmenty, na które dzieli się program?

Moja odpowiedź: tak (myślałem, że to było łatwe) Stack, Data, Code, Heap

P: Więc powiedz mi: które segmenty dzielą wątki?

Nie mogłem odpowiedzieć na to pytanie i ostatecznie powiedziałem je wszystkie.

Czy ktoś może przedstawić prawidłowe i imponujące odpowiedzi dotyczące różnicy między procesem a wątkiem?


9
Wątki dzielą tę samą wirtualną przestrzeń adresową , proces nie.
Benoit

Odpowiedzi:


177

Masz rację, ale wątki dzielą wszystkie segmenty oprócz stosu. Wątki mają niezależne stosy wywołań, jednak pamięć w innych stosach wątków jest nadal dostępna i teoretycznie możesz trzymać wskaźnik do pamięci w ramce lokalnego stosu innego wątku (chociaż prawdopodobnie powinieneś znaleźć lepsze miejsce na umieszczenie tej pamięci!).


27
Interesujące jest to, że chociaż wątki mają niezależne stosy wywołań, pamięć w innych stosach jest nadal dostępna.
Karthik Balaguru

1
tak - zastanawiam się, czy dopuszczalny jest dostęp do pamięci w innych stosach między wątkami? Dopóki masz pewność, że nie próbujesz odwoływać się do stosu, który został zwolniony, nie jestem pewien, czy mam z tym problem?
bph

2
@bph: Możliwe jest uzyskanie dostępu do pamięci stosu innego wątku, ale ze względu na dobrą praktykę inżynierii oprogramowania nie powiedziałbym, że jest to dopuszczalne .
Greg Hewgill,

1
Dostęp do, zwłaszcza pisania do stosów innych wątków, łączy się z kilkoma implementacjami śmieci. Można to jednak uzasadnić błędem implementacji GC.
yyny

56

Z Wikipedii (myślę, że to byłaby bardzo dobra odpowiedź dla ankietera: P)

Wątki różnią się od tradycyjnych wielozadaniowych procesów systemu operacyjnego tym, że:

  • procesy są zwykle niezależne, a wątki istnieją jako podzbiory procesu
  • procesy przenoszą znaczne informacje o stanie, podczas gdy wiele wątków w ramach stanu współużytkowania procesu, a także pamięci i innych zasobów
  • procesy mają osobne przestrzenie adresowe, podczas gdy wątki współużytkują swoją przestrzeń adresową
  • procesy współdziałają tylko poprzez dostarczone przez system mechanizmy komunikacji między procesami.
  • Przełączanie kontekstu między wątkami w tym samym procesie jest zazwyczaj szybsze niż przełączanie kontekstu między procesami.

2
o punkcie nr 2 powyżej: W przypadku wątków również CPU zachowuje kontekst.
Jack

49

Należy naprawdę podkreślić, że pytanie to ma dwa aspekty - aspekt teoretyczny i aspekt implementacyjny.

Najpierw spójrzmy na aspekt teoretyczny. Musisz zrozumieć, czym jest proces, aby zrozumieć różnicę między procesem a wątkiem i co jest między nimi wspólne.

W sekcji 2.2.2 Klasyczny model wątku w nowoczesnych systemach operacyjnych 3e autorstwa Tanenbaum:

Model procesu opiera się na dwóch niezależnych koncepcjach: grupowaniu zasobów i wykonywaniu. Czasami warto je rozdzielić; tutaj pojawiają się wątki ...

On kontynuuje:

Jednym ze sposobów patrzenia na proces jest to, że jest to sposób grupowania powiązanych zasobów. Proces ma przestrzeń adresową zawierającą tekst i dane programu, a także inne zasoby. Zasoby te mogą obejmować otwarte pliki, procesy potomne, oczekujące alarmy, procedury obsługi sygnałów, informacje księgowe i inne. Łącząc je w formie procesu, można nimi łatwiej zarządzać. Inną koncepcją procesu jest wątek wykonania, zwykle skracany do samego wątku. Wątek ma licznik programu, który śledzi, która instrukcja ma zostać wykonana w następnej kolejności. Posiada rejestry, które przechowują bieżące zmienne robocze. Ma stos, który zawiera historię wykonania, z jedną ramką dla każdej procedury wywoływanej, ale jeszcze nie zwróconej. Chociaż wątek musi zostać wykonany w pewnym procesie, wątek i jego proces są różnymi koncepcjami i mogą być traktowane osobno. Procesy są używane do grupowania zasobów; wątki to jednostki zaplanowane do wykonania na CPU.

Dalej znajduje się następująca tabela:

Per process items             | Per thread items
------------------------------|-----------------
Address space                 | Program counter
Global variables              | Registers
Open files                    | Stack
Child processes               | State
Pending alarms                |
Signals and signal handlers   |
Accounting information        |

To, czego potrzebujesz, aby wątki działały. Jak zauważyli inni, segmenty są szczegółami implementacji zależnymi od systemu operacyjnego.


2
To świetne wytłumaczenie. Ale prawdopodobnie należy to jakoś powiązać z pytaniem, by uznać je za „odpowiedź”
katalizator294

Jeśli chodzi o tabelę, czy program nie rejestruje rejestru? a „stan” wątku, przechwycony w wartości rejestrów? Brakuje mi również wskaźnika do uruchamianego kodu (wskaźnik do tekstu procesu)
onlycparra

29

Powiedz ankieterowi, że zależy to wyłącznie od wdrożenia systemu operacyjnego.

Weźmy na przykład Windows x86. Istnieją tylko 2 segmenty [1], Kod i Dane. Oba są odwzorowane na całą przestrzeń adresową 2 GB (liniową, użytkownika). Baza = 0, limit = 2 GB. Zrobiliby taki, ale x86 nie pozwala na segmentowanie zarówno odczytu / zapisu, jak i wykonania. Zrobili więc dwa i ustawili CS, aby wskazywał deskryptor kodu, a reszta (DS, ES, SS itd.) Wskazywała na drugi [2]. Ale oba wskazują na te same rzeczy!

Osoba przeprowadzająca wywiad z tobą ukryła założenie, że nie oświadczył, a to głupia sztuczka do wyciągnięcia.

Jeśli chodzi o

P: Więc powiedz mi, jaki udział w wątku segmentu?

Segmenty nie mają znaczenia dla pytania, przynajmniej w systemie Windows. Wątki dzielą całą przestrzeń adresową. Jest tylko 1 segment stosu, SS, i wskazuje dokładnie na te same rzeczy, co DS, ES i CS [2]. To znaczy cała cholerna przestrzeń użytkownika . 0–2 GB Oczywiście nie oznacza to, że wątki mają tylko 1 stos. Oczywiście każdy ma swój własny stos, ale do tego celu nie są używane segmenty x86.

Może * nix robi coś innego. Kto wie. Przesłanka, na której opierało się pytanie, została złamana.


  1. Przynajmniej dla przestrzeni użytkownika.
  2. Od ntsd notepad:cs=001b ss=0023 ds=0023 es=0023

1
Tak ... Segmenty zależą od systemu operacyjnego i kompilatora / linkera. Czasami istnieje oddzielny segment BSS od segmentu DATA. Czasami istnieje RODATA (dane takie jak ciągi ciągłe, które mogą znajdować się na stronach oznaczonych tylko do odczytu). Niektóre systemy nawet dzielą DANE na MAŁE DANE (dostępne z bazy + 16-bitowe przesunięcie) i (FAR) DANE (do uzyskania dostępu wymagane jest przesunięcie 32-bitowe). Możliwe jest również, że istnieje dodatkowy segment danych TLS (wątek lokalny sklep), który jest generowany dla poszczególnych wątków
Adisak,

5
Ah nie! Mylicie segmenty z sekcjami! Sekcje to sposób, w jaki linker dzieli moduł na części (dane, rdata, tekst, bss itp.) Zgodnie z opisem. Ale mówię o segmentach określonych w sprzęcie Intel / Amd x86. W ogóle nie związany z kompilatorami / linkerami. Mam nadzieję, że to ma sens.
Alex Budovski,

Jednak Adisak ma rację co do sklepu Thread Local. Jest prywatny dla wątku i nie jest udostępniany. Znam system operacyjny Windows i nie jestem pewien innego systemu operacyjnego.
Jack

20

Ogólnie wątki nazywane są lekkimi procesami. Jeśli podzielimy pamięć na trzy sekcje, będzie to: Kod, dane i Stos. Każdy proces ma swój własny kod, sekcje danych i stosu, dlatego czas przełączania kontekstu jest nieco długi. Aby skrócić czas przełączania kontekstu, ludzie wymyślili koncepcję wątku, który dzieli segment danych i kodu z innym wątkiem / procesem i ma własny segment STOSOWANIA.


Zapomniałeś kupy. Sterty, jeśli się nie mylę, powinny być dzielone między wątkami
Phate

20

Proces ma segmenty kodu, danych, sterty i stosu. Teraz wskaźnik instrukcji (IP) wątku LUB wątków wskazuje segment kodu procesu. Segmenty danych i sterty są wspólne dla wszystkich wątków. A co z obszarem stosu? Co to właściwie jest obszar stosu? Jest to obszar utworzony przez proces tylko do użycia przez wątek ... ponieważ stosy mogą być używane znacznie szybciej niż stosy itp. Obszar stosu procesu jest podzielony na wątki, tzn. Jeśli są 3 wątki, wówczas obszar stosu procesu jest podzielony na 3 części, a każda z nich jest podana do 3 wątków. Innymi słowy, kiedy mówimy, że każdy wątek ma swój własny stos, stos ten jest w rzeczywistości częścią obszaru stosu procesu przypisanego do każdego wątku. Po zakończeniu wykonywania wątku stos wątku jest odzyskiwany przez proces. W rzeczywistości, nie tylko stos procesu jest podzielony na wątki, ale cały zestaw rejestrów używanych przez wątek, takich jak SP, PC i rejestry stanu, są rejestrami procesu. Jeśli chodzi o udostępnianie, obszary kodu, danych i sterty są wspólne, a obszar stosu jest po prostu podzielony na wątki.


13

Wątki dzielą kod i segmenty danych oraz stertę, ale nie dzielą stosu.


11
Istnieje różnica między „zdolnością dostępu do danych w stosie” a udostępnianiem stosu. Te wątki mają własne stosy, które są wypychane i wyskakiwane, gdy wywołują metody.
Kevin Peterson

2
Oba są równie poprawnymi poglądami. Tak, każdy wątek ma swój własny stos, w tym sensie, że między wątkami i stosami istnieje relacja jeden do jednego, a każdy wątek ma przestrzeń, z której korzysta na swoje normalne użycie stosu. Ale są również w pełni współdzielonymi zasobami procesowymi i, jeśli to pożądane, każdy wątek może uzyskać dostęp do stosu dowolnego innego wątku tak łatwo, jak własnego.
David Schwartz

@DavidSchwartz, czy mogę streścić twój punkt, jak poniżej: Każdy wątek ma swój własny stos, a stos składa się z 2 części - pierwszej części, która jest dzielona między wątkami przed procesem wielowątkowym, a drugiej części, która jest wypełniana, gdy wątek będący właścicielem działa. Zgadzam się?
FaceBro 18.04.15

2
@nextTide Nie ma dwóch części. Stosy są wspólne, kropka. Każdy wątek ma swój własny stos, ale są one również udostępniane. Być może dobrą analogią jest sytuacja, gdy ty i twoja żona macie samochód, ale możecie sobie nawzajem korzystać z samochodów w dowolnym momencie.
David Schwartz,

5

Wątki współużytkują dane i kod, podczas gdy procesy nie. Stos nie jest udostępniany dla obu.

Procesy mogą również współużytkować pamięć, a dokładniej kod, na przykład po a Fork(), ale jest to szczegół implementacji i optymalizacja (systemu operacyjnego). Kod współdzielony przez wiele procesów zostanie (mam nadzieję) zduplikowany przy pierwszym zapisie do kodu - jest to znane jako kopiowanie przy zapisie . Nie jestem pewien co do dokładnej semantyki dla kodu wątków, ale zakładam kod współdzielony.

           Przetwarzaj wątek

   Stos prywatny prywatny
   Udostępnione dane prywatne
   Kod prywatny 1   wspólny 2

1 Kod jest logicznie prywatny, ale może być udostępniany ze względu na wydajność. 2 Nie jestem w 100% pewien.


Powiedziałbym, że segment kodu (segment tekstowy), w przeciwieństwie do danych, prawie zawsze jest czytany tylko na większości architektur.
Jorge Córdoba

4

Wątki udostępniają wszystko [1]. Dla całego procesu istnieje jedna przestrzeń adresowa.

Każdy wątek ma swój własny stos i rejestry, ale wszystkie stosy wątków są widoczne we wspólnej przestrzeni adresowej.

Jeśli jeden wątek przydzieli jakiś obiekt na stosie i wyśle ​​adres do innego wątku, oba będą miały równy dostęp do tego obiektu.


W rzeczywistości, po prostu zauważyłem szerszy problem: Myślę, że mylące dwa zastosowania tego słowa segmencie .

Format pliku wykonywalnego (np. ELF) zawiera odrębne sekcje, które można nazwać segmentami, zawierającymi skompilowany kod (tekst), zainicjowane dane, symbole linkera, informacje debugowania itp. Nie ma segmentów sterty lub stosu tutaj, ponieważ są to konstrukcje tylko do uruchamiania.

Te segmenty plików binarnych mogą być mapowane osobno w przestrzeni adresowej procesu, z różnymi uprawnieniami (np. Plik wykonywalny tylko do odczytu dla kodu / tekstu i plik wykonywalny kopiowania przy zapisie dla danych inicjowanych).

Obszary tej przestrzeni adresowej są wykorzystywane do różnych celów, takich jak alokacja sterty i stosy wątków, zgodnie z konwencją (wymuszoną przez biblioteki środowiska wykonawczego języka). To wszystko jest tylko pamięć i prawdopodobnie nie jest podzielona na segmenty, chyba że pracujesz w trybie wirtualnym 8086. Stos każdego wątku jest fragmentem pamięci przydzielanej podczas tworzenia wątku, przy czym bieżący górny adres stosu jest przechowywany w rejestrze wskaźnika stosu, a każdy wątek utrzymuje swój własny wskaźnik stosu wraz z innymi rejestrami.


[1] OK, wiem: maski sygnałów, TSS / TSD itp. Przestrzeń adresowa, w tym wszystkie jej zmapowane segmenty programu, są jednak nadal współdzielone.


3

W środowisku x86 można podzielić tyle segmentów (do 2 ^ 16-1). Na to pozwalają dyrektywy ASM SEGMENT / ENDS, a operatorzy SEG i OFFSET umożliwiają inicjalizację rejestrów segmentów. CS: IP są zwykle inicjowane przez moduł ładujący, ale w przypadku DS, ES, SS aplikacja jest odpowiedzialna za inicjalizację. Wiele środowisk pozwala na tak zwane „uproszczone definicje segmentów”, takie jak .code, .data, .bss, .stack itp. Oraz, w zależności od „modelu pamięci” (mały, duży, kompaktowy itp.), Moduł ładujący inicjuje rejestry segmentów odpowiednio. Zwykle .data, .bss, .stack i inne zwykłe segmenty (nie robiłem tego od 20 lat, więc nie pamiętam wszystkich) są zgrupowane w jednej grupie - dlatego zwykle punkty DS, ES i SS są ten sam obszar, ale ma to jedynie na celu uproszczenie.

Zasadniczo wszystkie rejestry segmentów mogą mieć różne wartości w czasie wykonywania. Pytanie w rozmowie kwalifikacyjnej było więc prawidłowe: który z KODÓW, DANYCH i STOSOWANIA są współużytkowane przez wątki. Zarządzanie stertami to coś innego - to po prostu sekwencja połączeń z systemem operacyjnym. Ale co, jeśli w ogóle nie masz systemu operacyjnego, na przykład w systemie wbudowanym - czy nadal możesz mieć nowy / usunąć w kodzie?

Moja rada dla młodych ludzi - przeczytaj dobrą książkę do programowania w asemblerze. Wydaje się, że pod tym względem programy uniwersyteckie są dość słabe.


2

Oprócz pamięci globalnej wątki mają również wiele innych atrybutów (tj. Atrybuty te są globalne dla procesu, a nie specyficzne dla wątku). Te atrybuty obejmują:

  • identyfikator procesu i nadrzędny identyfikator procesu;
  • identyfikator grupy procesu i identyfikator sesji;
  • terminal kontrolny;
  • poświadczenia procesu (identyfikatory użytkownika i grupy);
  • otwarte deskryptory plików;
  • blokady rekordów utworzone za pomocą fcntl();
  • dyspozycje sygnałowe;
  • informacje związane z systemem plików: umask, bieżący katalog roboczy i katalog główny;
  • timery interwałowe ( setitimer()) i timery POSIX ( timer_create());
  • semadjWartości cofania ( ) semafora w systemie V (sekcja 47.8);
  • limity zasobów;
  • Czas pracy procesora (zwracany przez times());
  • zużyte zasoby (zwrócone przez getrusage()); i
  • niezła wartość (ustawiona przez setpriority()i nice()).

Wśród atrybutów, które są odrębne dla każdego wątku, są:

  • identyfikator wątku (sekcja 29.5);
  • maska ​​sygnału;
  • dane specyficzne dla wątku (sekcja 31.3);
  • alternatywny stos sygnału ( sigaltstack());
  • zmienna errno;
  • środowisko zmiennoprzecinkowe (patrz fenv(3));
  • polityka i priorytet planowania w czasie rzeczywistym (sekcje 35.2 i 35.3);
  • Powinowactwo procesora (specyficzne dla systemu Linux, opisane w sekcji 35.4);
  • możliwości (specyficzne dla systemu Linux, opisane w rozdziale 39); i
  • stos (zmienne lokalne i informacje o połączeniu wywołania funkcji).

Fragment: Interfejs programowania systemu Linux: Podręcznik programowania systemu Linux i UNIX, Michael Kerrisk , strona 619


0

Wątek udostępnia stertę (są badania nad stertą dla określonego wątku), ale bieżąca implementacja udostępnia stertę. (i oczywiście kod)


0

W trakcie procesu wszystkie wątki współużytkują zasoby systemowe, takie jak Pamięć sterty itp., Podczas gdy wątek ma własny stos

Więc twoja ans powinna być pamięcią sterty, którą wszystkie wątki współużytkują dla procesu.

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.