Przegląd elementów podstawowych synchronizacji

Platforma .NET udostępnia szereg typów, których można użyć do synchronizowania dostępu do współużytkowanego zasobu lub współrzędnych interakcji wątku.

Ważne

Użyj tego samego wystąpienia pierwotnego synchronizacji, aby chronić dostęp do udostępnionego zasobu. Jeśli używasz różnych wystąpień pierwotnych synchronizacji do ochrony tego samego zasobu, obejście ochrony zapewnianej przez typ pierwotny synchronizacji.

WaitHandle, klasa i lekkie typy synchronizacji

Wiele elementów pierwotnych synchronizacji platformy .NET pochodzi z System.Threading.WaitHandle klasy, która hermetyzuje natywną obsługę synchronizacji systemu operacyjnego i używa mechanizmu sygnalizacyjnego na potrzeby interakcji wątków. Klasy te obejmują:

  • System.Threading.Mutex, który udziela wyłącznego dostępu do zasobu udostępnionego. Stan mutexu jest sygnalizowany, jeśli żaden wątek nie jest jego właścicielem.
  • System.Threading.Semaphore, który ogranicza liczbę wątków, które mogą uzyskiwać dostęp do współużytkowanego zasobu lub puli zasobów jednocześnie. Stan semafora jest ustawiony na sygnał, gdy jego liczba jest większa niż zero, a niepodpisane, gdy jej liczba wynosi zero.
  • System.Threading.EventWaitHandle, który reprezentuje zdarzenie synchronizacji wątków i może być w stanie sygnalizowanym lub niepodpisanym.
  • System.Threading.AutoResetEvent, który pochodzi z EventWaitHandle elementu i po zasygnalizowaniu, automatycznie resetuje się do stanu niepodpisanego po zwolnieniu pojedynczego wątku oczekującego.
  • System.Threading.ManualResetEvent, który pochodzi z EventWaitHandle elementu i, gdy jest zasygnaliowany, pozostaje w stanie sygnałowym Reset , dopóki metoda nie zostanie wywołana.

W programie .NET Framework, ponieważ WaitHandle pochodzi z System.MarshalByRefObjectprogramu , te typy mogą służyć do synchronizowania działań wątków poza granicami domeny aplikacji.

W programach .NET Framework, .NET Core i .NET 5 lub nowszych niektóre z tych typów mogą reprezentować nazwane dojścia synchronizacji systemu, które są widoczne w całym systemie operacyjnym i mogą być używane do synchronizacji między procesami:

Aby uzyskać więcej informacji, zobacz dokumentację interfejsu WaitHandle API.

Uproszczone typy synchronizacji nie korzystają z podstawowych dojść systemu operacyjnego i zwykle zapewniają lepszą wydajność. Nie można ich jednak używać do synchronizacji między procesami. Użyj tych typów do synchronizacji wątków w jednej aplikacji.

Niektóre z tych typów to alternatywy dla typów pochodzących z WaitHandleelementu . Na przykład SemaphoreSlim jest to uproszczona alternatywa dla Semaphoreelementu .

Synchronizacja dostępu do zasobu udostępnionego

Platforma .NET udostępnia szereg typów pierwotnych synchronizacji w celu kontrolowania dostępu do udostępnionego zasobu przez wiele wątków.

klasa monitora

System.Threading.Monitor Klasa przyznaje wzajemnie wykluczający się dostęp do udostępnionego zasobu przez uzyskanie lub zwolnienie blokady obiektu, który identyfikuje zasób. Gdy blokada jest utrzymywana, wątek, który przechowuje blokadę, może ponownie uzyskać i zwolnić blokadę. Każdy inny wątek nie może nabyć blokady, a Monitor.Enter metoda czeka na zwolnienie blokady. Metoda Enter uzyskuje zwolniony blokadę. Można również użyć Monitor.TryEnter metody , aby określić czas, w którym wątek próbuje uzyskać blokadę. Monitor Ponieważ klasa ma koligację wątków, wątek, który uzyskał blokadę, musi zwolnić blokadę, wywołując metodę Monitor.Exit .

Można koordynować interakcję wątków, które uzyskują blokadę na tym samym obiekcie przy użyciu Monitor.Waitmetod , Monitor.Pulsei Monitor.PulseAll .

Aby uzyskać więcej informacji, zobacz dokumentację interfejsu Monitor API.

Uwaga

Użyj instrukcji lock w języku C# i instrukcji SyncLock w języku Visual Basic, aby zsynchronizować dostęp do udostępnionego zasobu zamiast bezpośrednio używać Monitor klasy. Te instrukcje są implementowane przy użyciu Enter metod i Exit i i try…finally bloku w celu zapewnienia, że nabyty blokada jest zawsze zwalniana.

Mutex — Klasa

Klasa System.Threading.Mutex , na przykład Monitor, udziela wyłącznego dostępu do udostępnionego zasobu. Użyj jednego z przeciążeń metody Mutex.WaitOne , aby zażądać własności mutexu. Podobnie jak Monitor, Mutex ma koligację wątku, a wątek, który nabył mutex, musi go zwolnić, wywołując metodę Mutex.ReleaseMutex .

Mutex W przeciwieństwie do Monitorklasy można używać do synchronizacji między procesami. W tym celu należy użyć nazwanego mutexu, który jest widoczny w całym systemie operacyjnym. Aby utworzyć nazwane wystąpienie mutex, użyj konstruktora Mutex, który określa nazwę. Możesz również wywołać metodę Mutex.OpenExisting , aby otworzyć istniejący nazwany mutex systemu.

Aby uzyskać więcej informacji, zobacz artykuł Mutexes i dokumentacja interfejsu Mutex API.

Struktura SpinLock

Struktura System.Threading.SpinLock , na przykład Monitor, udziela wyłącznego dostępu do udostępnionego zasobu na podstawie dostępności blokady. Podczas SpinLock próby uzyskania blokady, która jest niedostępna, czeka w pętli, wielokrotnie sprawdzając, aż blokada stanie się dostępna.

Aby uzyskać więcej informacji na temat korzyści i wad używania blokady spin, zobacz artykuł SpinLock i dokumentacja interfejsu SpinLock API.

ReaderWriterLockSlim, klasa

Klasa System.Threading.ReaderWriterLockSlim udziela wyłącznego dostępu do udostępnionego zasobu do zapisu i umożliwia wielu wątkom jednoczesne uzyskiwanie dostępu do zasobu do odczytu. Możesz użyć ReaderWriterLockSlim polecenia , aby zsynchronizować dostęp do udostępnionej struktury danych, która obsługuje operacje odczytu bezpiecznego wątkowo, ale wymaga wyłącznego dostępu do wykonywania operacji zapisu. Gdy wątek żąda wyłącznego dostępu (na przykład przez wywołanie ReaderWriterLockSlim.EnterWriteLock metody ), kolejne żądania czytelnika i modułu zapisywania blokują, dopóki wszyscy istniejący czytelnicy nie zamkną blokady, a zapis wszedł i zamknął blokadę.

Aby uzyskać więcej informacji, zobacz dokumentację interfejsu ReaderWriterLockSlim API.

Klasy Semaphore i SemaphoreSlim

Klasy System.Threading.Semaphore i System.Threading.SemaphoreSlim ograniczają liczbę wątków, które mogą uzyskiwać dostęp do współużytkowanego zasobu lub puli zasobów jednocześnie. Dodatkowe wątki, które żądają zasobu czekać, aż dowolny wątek zwolni semafor. Ponieważ semafor nie ma koligacji wątku, wątek może uzyskać semafor, a drugi może go zwolnić.

SemaphoreSlim jest uproszczoną alternatywą Semaphore dla metody i może być używana tylko do synchronizacji w ramach jednej granicy procesu.

W systemie Windows można użyć Semaphore synchronizacji między procesami. W tym celu utwórz Semaphore wystąpienie reprezentujące nazwany semafor systemowy przy użyciu jednego z konstruktorów Semaphore, który określa nazwę lub metodę Semaphore.OpenExisting . SemaphoreSlim nie obsługuje nazwanych semaforów systemowych.

Aby uzyskać więcej informacji, zobacz artykuł Semaphore and SemaphoreSlim i dokumentacja interfejsu Semaphore API.SemaphoreSlim

Interakcja wątkowa lub sygnalizowanie

Interakcja wątku (lub sygnalizowanie wątków) oznacza, że wątek musi czekać na powiadomienie lub sygnał z co najmniej jednego wątku, aby kontynuować. Jeśli na przykład wątek A wywołuje metodę Thread.Join wątku B, wątek A zostanie zablokowany do momentu zakończenia wątku B. Typy pierwotne synchronizacji opisane w poprzedniej sekcji zapewniają inny mechanizm sygnalizowania: zwalniając blokadę, wątek powiadamia inny wątek, który może kontynuować, uzyskując blokadę.

W tej sekcji opisano dodatkowe konstrukcje sygnalizacyjne dostarczane przez platformę .NET.

Klasy EventWaitHandle, AutoResetEvent, ManualResetEvent i ManualResetEventSlim

Klasa System.Threading.EventWaitHandle reprezentuje zdarzenie synchronizacji wątków.

Zdarzenie synchronizacji może być w stanie niepodpisanym lub zasygnalizowanym. Gdy stan zdarzenia jest niepodpisany, wątek wywołujący przeciążenie zdarzenia WaitOne jest blokowany do momentu zasygnaliowania zdarzenia. Metoda EventWaitHandle.Set ustawia stan zdarzenia na sygnalizowany.

Zachowanie EventWaitHandle , które zostało zasygnaliowane, zależy od jego trybu resetowania:

W systemie Windows można użyć EventWaitHandle synchronizacji między procesami. W tym celu utwórz EventWaitHandle wystąpienie reprezentujące nazwane zdarzenie synchronizacji systemu przy użyciu jednego z konstruktorów EventWaitHandle, które określa nazwę lub metodę EventWaitHandle.OpenExisting .

Aby uzyskać więcej informacji, zobacz artykuł EventWaitHandle . Aby zapoznać się z dokumentacją interfejsu API, zobacz EventWaitHandle, AutoResetEvent, ManualResetEventi ManualResetEventSlim.

CountdownEvent, klasa

Klasa System.Threading.CountdownEvent reprezentuje zdarzenie, które staje się ustawiane, gdy jego liczba wynosi zero. Chociaż CountdownEvent.CurrentCount jest większy niż zero, wątek, który wywołuje CountdownEvent.Wait , jest blokowany. Wywołanie metody CountdownEvent.Signal w celu dekrementacji liczby zdarzeń.

W przeciwieństwie do ManualResetEvent funkcji lub ManualResetEventSlim, której można użyć do odblokowania wielu wątków za pomocą sygnału z jednego wątku, można użyć CountdownEvent do odblokowania co najmniej jednego wątku z sygnałami z wielu wątków.

Aby uzyskać więcej informacji, zobacz artykuł CountdownEvent i dokumentacja interfejsu CountdownEvent API.

Klasa bariery

Klasa System.Threading.Barrier reprezentuje barierę wykonywania wątku. Wątek, który wywołuje Barrier.SignalAndWait metodę sygnałów, że dotarł do bariery i czeka, aż inne wątki uczestnika osiągną barierę. Gdy wszystkie wątki uczestnika osiągną barierę, kontynuują i barierę są resetowane i mogą być ponownie używane.

Można użyć Barrier , gdy co najmniej jeden wątek wymaga wyników innych wątków przed przejściem do następnej fazy obliczeń.

Aby uzyskać więcej informacji, zobacz artykuł Bariera i dokumentacja interfejsu Barrier API.

Interlocked — Klasa

Klasa System.Threading.Interlocked udostępnia metody statyczne, które wykonują proste operacje niepodzielne na zmiennej. Te operacje niepodzielne obejmują dodawanie, zwiększanie i dekrementację, wymianę i wymianę warunkową, która zależy od porównania, oraz operację odczytu wartości całkowitej 64-bitowej.

Aby uzyskać więcej informacji, zobacz dokumentację interfejsu Interlocked API.

SpinWait, struktura

Struktura System.Threading.SpinWait zapewnia obsługę oczekiwania opartego na spin-based. Możesz użyć go, gdy wątek musi poczekać na zasygnaliowanie zdarzenia lub spełnić warunek, ale gdy rzeczywisty czas oczekiwania powinien być krótszy niż czas oczekiwania wymagany przez użycie uchwytu oczekiwania lub przez zablokowanie wątku w inny sposób. Za pomocą polecenia SpinWaitmożna określić krótki okres czasu do uruchomienia podczas oczekiwania, a następnie uzyskać (na przykład przez oczekiwanie lub spanie) tylko wtedy, gdy warunek nie został spełniony w określonym czasie.

Aby uzyskać więcej informacji, zobacz artykuł SpinWait i dokumentacja interfejsu SpinWait API.

Zobacz też