Słyszałem te słowa związane z programowaniem równoległym, ale jaka jest między nimi różnica?
concurrency
locking
mutex
semaphore
zwycięzca
źródło
źródło
Odpowiedzi:
Blokada umożliwia wejście tylko jednego wątku do części, która jest zablokowana, a blokada nie jest współdzielona z żadnymi innymi procesami.
Muteks jest taki sam jak blokada, ale może być ogólnosystemowy (współdzielony przez wiele procesów).
Semafora działa tak samo jak mutex, ale pozwala x liczba wątków wejść, to może być wykorzystane na przykład ograniczyć liczbę CPU, IO lub ubijania intensywnych zadań uruchomionych w tym samym czasie.
Bardziej szczegółowy post o różnicach między muteksem a semaforem znajduje się tutaj .
Masz również blokady odczytu / zapisu, które pozwalają na nieograniczoną liczbę czytników lub 1 pisarz w danym momencie.
źródło
Istnieje wiele nieporozumień dotyczących tych słów.
To jest z poprzedniego postu ( https://stackoverflow.com/a/24582076/3163691 ), który doskonale pasuje tutaj:
1) Sekcja krytyczna = Obiekt użytkownika używany do umożliwienia wykonania tylko jednego aktywnego wątku z wielu innych w ramach jednego procesu . Pozostałe niewybrane wątki (@ pozyskanie tego obiektu) są uśpione .
[Brak możliwości przetwarzania, bardzo prymitywny obiekt].
2) Mutex Semaphore (alias Mutex) = Obiekt jądra używany do umożliwienia wykonania tylko jednego aktywnego wątku z wielu innych, wśród różnych procesów . Pozostałe niewybrane wątki (@ pozyskanie tego obiektu) są uśpione . Ten obiekt obsługuje własność wątku, powiadomienie o zakończeniu wątku, rekurencję (wielokrotne wywołania „pozyskaj” z tego samego wątku) i „unikanie priorytetowej inwersji”.
Możliwości międzyprocesowe, bardzo bezpieczny w użyciu, rodzaj obiektu synchronizacji „wysokiego poziomu”.
3) Counting Semaphore (alias Semaphore) = Obiekt jądra służący do wykonywania grupy aktywnych wątków z wielu innych. Pozostałe niewybrane wątki (@ pozyskanie tego obiektu) są uśpione .
[Zdolność międzyprocesowa nie jest jednak zbyt bezpieczna w użyciu, ponieważ brakuje w niej następujących atrybutów „mutex”: powiadomienia o zakończeniu wątku, rekurencji?, „Unikania inwersji priorytetów”? Itd.].
4) A teraz, mówiąc o „spinlockach”, najpierw kilka definicji:
Region krytyczny = region pamięci współdzielony przez 2 lub więcej procesów.
Blokada = zmienna, której wartość pozwala lub odmawia wejścia do „regionu krytycznego”. (Może być zaimplementowany jako prosta „flaga boolowska”).
Zajęte oczekiwanie = Ciągłe testowanie zmiennej, aż pojawi się jakaś wartość.
Wreszcie:
Spin-lock (inaczej Spinlock) = Blokada, która wykorzystuje zajęte oczekiwanie . ( Pozyskiwanie blokady odbywa się za pomocą xchg lub podobnych operacji atomowych ).
[Brak uśpienia wątku, najczęściej używany tylko na poziomie jądra. Nieefektywne dla kodu poziomu użytkownika].
Jako ostatni komentarz, nie jestem pewien, ale mogę postawić ci kilka dużych dolarów, że powyższe pierwsze 3 obiekty synchronizujące (# 1, # 2 i # 3) wykorzystują tę prostą bestię (# 4) w ramach ich implementacji.
Miłego dnia!.
Bibliografia:
Koncepcje czasu rzeczywistego dla systemów wbudowanych autorstwa Qing Li z Caroline Yao (CMP Books).
-Nowoczesne systemy operacyjne (3.) autorstwa Andrew Tanenbaum (Pearson Education International).
-Programowanie aplikacji dla Microsoft Windows (4.) autorstwa Jeffrey'a Richtera (Microsoft Programming Series).
Możesz także rzucić okiem na: https://stackoverflow.com/a/24586803/3163691
źródło
Większość problemów można rozwiązać za pomocą (i) samych blokad, (ii) tylko semaforów, ... lub (iii) kombinacji obu! Jak zapewne zauważyłeś, są one bardzo podobne: oba zapobiegają warunkom wyścigu , oba mają
acquire()
/release()
operacje, oba powodują zablokowanie / podejrzenie zerowej lub większej liczby wątków ... Naprawdę, zasadnicza różnica polega wyłącznie na tym , jak się blokują i odblokowują .W przypadku obu blokad / semaforów próba wywołania,
acquire()
gdy operacja podstawowa znajduje się w stanie 0, powoduje zawieszenie wątku wywołującego. W przypadku zamków - próby uzyskania zamka są w stanie 1 zakończone powodzeniem. W przypadku semaforów - próby uzyskania blokady w stanach {1, 2, 3, ...} są udane.W przypadku blokad w stanie 0, jeśli ten sam wątek, który wcześniej wywołał
acquire()
, teraz wywołuje polecenie release, wówczas wydanie jest udane. Jeśli próbował tego inny wątek - to, co się stanie, zależy od implementacji / biblioteki (zwykle próba jest ignorowana lub zgłaszany jest błąd). W przypadku semaforów w stanie 0 każdy wątek może wywołać zwolnienie i zakończy się powodzeniem (niezależnie od tego, który wątek poprzednio użył, aby ustawić semafor w stanie 0).Z poprzedniej dyskusji możemy zobaczyć, że zamki mają pojęcie właściciela (jedynym wątkiem, który może wywołać release, jest właściciel), podczas gdy semafory nie mają właściciela (każdy wątek może wywołać release na semaforze).
Powoduje to wiele zamieszania, ponieważ w praktyce jest wiele odmian tej definicji wysokiego poziomu.
Ważne odmiany do rozważenia :
acquire()
/release()
- [zmienia się masowo ]Zależy to od twojej książki / wykładowcy / języka / biblioteki / środowiska.
Oto krótka prezentacja z opisem, w jaki sposób niektóre języki odpowiadają na te szczegóły.
C, C ++ ( pthreads )
pthread_mutex_t
. Domyślnie nie można ich udostępniać innym procesom (PTHREAD_PROCESS_PRIVATE
), jednak mutex mają atrybut o nazwie pshared . Po ustawieniu muteks jest dzielony między procesy (PTHREAD_PROCESS_SHARED
).sem_t
. Podobnie jak muteksy, semafory mogą być współużytkowane przez trzy procesy wielu procesów lub utrzymywane w tajemnicy dla wątków jednego procesu. Zależy to od dostarczonego argumentu psharedsem_init
.python ( threading.py )
threading.RLock
) jest w większości taka sama jak C / C ++pthread_mutex_t
S. Obaj są ponownie wysłani . Oznacza to, że można je odblokować tylko przez ten sam wątek, który je zablokował. Dzieje się tak, gdysem_t
semafory,threading.Semaphore
semafory itheading.Lock
zamki nie są ponownie wysyłane - ponieważ w tym przypadku każdy wątek może odblokować / zablokować semafor.threading.Semaphore
) jest w większości takie same, jaksem_t
. Chociaż zsem_t
, kolejka identyfikatorów wątków jest używana do zapamiętywania kolejności, w której wątki zostały zablokowane podczas próby zablokowania, gdy jest zablokowane. Gdy wątek odblokowuje semafor, pierwszy wątek w kolejce (jeśli taki istnieje) zostaje wybrany jako nowy właściciel. Identyfikator wątku jest usuwany z kolejki, a semafor zostaje ponownie zablokowany. Jednak zthreading.Semaphore
, zamiast kolejki używany jest zestaw, więc kolejność blokowania wątków nie jest zapisywana - każdy wątek w zestawie może zostać wybrany jako następny właściciel.Java ( java.util.concurrent )
java.util.concurrent.ReentrantLock
) jest w większości taka sama jak C / C ++pthread_mutex_t
„S i Pythonathreading.RLock
tym, że sposób realizuje wielowejściowy zamka. Udostępnianie blokad między procesami jest trudniejsze w Javie, ponieważ JVM działa jako pośrednik. Jeśli wątek próbuje odblokować zamek, którego nie posiada,IllegalMonitorStateException
zostaje wyrzucony.java.util.concurrent.Semaphore
) jest w większości takie same, jaksem_t
ithreading.Semaphore
. Konstruktor semaforów Java akceptuje parametr boolean fairness , który kontroluje, czy użyć zestawu (false), czy kolejki (true) do przechowywania oczekujących wątków.Teoretycznie semafory są często omawiane, ale w praktyce semafory nie są tak często używane. Semafor utrzymuje stan tylko jednej liczby całkowitej, więc często jest raczej mało elastyczny i wiele jest potrzebnych naraz - co powoduje trudności w zrozumieniu kodu. Ponadto fakt, że dowolny wątek może zwolnić semafor, jest czasem niepożądany. Zamiast tego używane są bardziej zorientowane obiektowo / nadrzędne poziomy synchronizacji / abstrakcje, takie jak „zmienne warunkowe” i „monitory”.
źródło
Spójrz na samouczek wielowątkowości autorstwa Johna Kopplina.
W sekcji Synchronizacja między wątkami wyjaśnia różnice między zdarzeniem, blokadą, muteksem, semaforem, licznikiem czasu oczekiwania
źródło
Spróbuję opisać to przykładami:
Blokada: przykładem
lock
może być wspólny słownik, do którego dodawane są elementy (które muszą mieć unikalne klucze).Blokada zapewni, że jeden wątek nie wejdzie w mechanizm kodu, który sprawdza, czy element znajduje się w słowniku, podczas gdy inny wątek (czyli w sekcji krytycznej) już przeszedł to sprawdzenie i dodaje element. Jeśli inny wątek spróbuje wprowadzić zablokowany kod, zaczeka (zostanie zablokowany), aż obiekt zostanie zwolniony.
Semafor: Powiedzmy, że masz pulę połączeń, a następnie pojedynczy wątek może zarezerwować jeden element w puli, czekając, aż semafor uzyska połączenie. Następnie korzysta z połączenia, a po zakończeniu pracy zwalnia połączenie, zwalniając semafor.
Przykład kodu, który kocham, to bramkarz podany przez @Patric - oto:
Mutex Jest dość
Semaphore(1,1)
powszechny i często używany na całym świecie (szerokie zastosowanie, w przeciwnym razielock
bardziej odpowiednie). Jednego użyłby globalnyMutex
podczas usuwania węzła z globalnie dostępnej listy (ostatnią rzeczą, którą chcesz, aby inny wątek coś zrobił podczas usuwania węzła). Gdy zdobędziesz,Mutex
jeśli inny wątek spróbuje go uzyskaćMutex
, zostanie on uśpiony, dopóki SAMY wątek, który go nabył,Mutex
go nie zwolni.Dobrym przykładem tworzenia globalnego muteksu jest @deepee
następnie użyj:
Mam nadzieję, że to pozwoli Ci zaoszczędzić trochę czasu.
źródło
Wikipedia ma świetną sekcję na temat różnic między semaforami i muteksami :
źródło
Rozumiem, że muteks jest przeznaczony do użycia tylko w jednym procesie, ale w wielu wątkach, podczas gdy semafor może być używany w wielu procesach i odpowiadających im zestawach wątków.
Muteks jest również binarny (jest zablokowany lub odblokowany), podczas gdy semafor ma pojęcie liczenia lub kolejkę więcej niż jednego żądania blokady i odblokowania.
Czy ktoś może zweryfikować moje wyjaśnienie? Mówię w kontekście Linuksa, w szczególności Red Hat Enterprise Linux (RHEL) wersja 6, która wykorzystuje jądro 2.6.32.
źródło
Wykorzystanie programowania C w wariancie Linux jako podstawowy przypadek dla przykładów.
Zamek:
• Zwykle bardzo prosta konstrukcja binarna działająca albo zablokowana, albo odblokowana
• Brak koncepcji własności wątku, priorytetu, sekwencjonowania itp.
• Zwykle blokada wirowania, w której nić stale sprawdza dostępność zamków.
• Zwykle opiera się na operacjach atomowych, np. Testuj i ustawiaj, porównuj i wymieniaj, pobieraj i dodawaj itp.
• Zwykle wymaga wsparcia sprzętowego dla operacji atomowych.
Blokady plików:
• Zwykle używany do koordynowania dostępu do pliku za pośrednictwem wielu procesów.
• Wiele procesów może utrzymywać blokadę odczytu, jednak gdy jakikolwiek pojedynczy proces posiada blokadę zapisu, żaden inny proces nie może uzyskać blokady odczytu lub zapisu.
• Przykład: flock, fcntl itp.
Mutex:
• Wywołania funkcji Mutex zwykle działają w przestrzeni jądra i powodują wywołania systemowe.
• Wykorzystuje pojęcie własności. Tylko wątek, który obecnie zawiera muteks, może go odblokować.
• Mutex nie jest rekurencyjny (wyjątek: PTHREAD_MUTEX_RECURSIVE).
• Zwykle używany w powiązaniu ze zmiennymi warunkowymi i przekazywany jako argumenty np. Pthread_cond_signal, pthread_cond_wait itp.
• Niektóre systemy UNIX zezwalają na używanie muteksu w wielu procesach, chociaż może to nie być wymuszone we wszystkich systemach.
Semafor:
• Jest to liczba całkowita utrzymywana przez jądro, której wartości nie mogą spaść poniżej zera.
• Można go użyć do synchronizacji procesów.
• Wartość semafora może być ustawiona na wartość większą niż 1, w którym to przypadku zwykle wskazuje liczbę dostępnych zasobów.
• Semafor, którego wartość jest ograniczona do 1 i 0, jest określany jako semafor binarny.
źródło
Supporting ownership
,maximum number of processes share lock
amaximum number of allowed processes/threads in critical section
są to trzy główne czynniki, które określają nazwę / typ współbieżnego obiektu z ogólną nazwąlock
. Ponieważ wartości tych czynników są binarne (mają dwa stany), możemy je podsumować w tabeli 3 * 8 przypominającej prawdę.Zmodyfikuj lub rozwiń tę tabelę, opublikowałem ją jako tabelę ascii, aby była edytowalna :)
źródło