Semaphore i SemaphoreSlim

Klasa System.Threading.Semaphore reprezentuje semafor nazwany, zarówno systemowy, jak i lokalny. Jest to cienka warstwa wokół obiektu semafora Win32. Semeafory Win32 to semafory zliczające, które kontrolują dostęp do puli zasobów.

Klasa SemaphoreSlim reprezentuje lekki, szybki semafor, którego można użyć do oczekiwania w ramach jednego procesu, gdy oczekuje się, że czas oczekiwania będzie krótki. W fazie oczekiwania procesora CPU aktywnie się obraca — nie jest bezczynny. Jak krótki "krótki" musi zależeć od charakteru oczekiwania: jeśli wątki rywalizują o zasoby procesora CPU, wirujący wątek zużywa czas procesora CPU, więc oczekiwanie powinno być bardzo krótkie, mierzone w mikrosekundach. Jeśli oczekiwanie dotyczy zasobu niezwiązanego z procesorem CPU (takiego jak operacje we/wy), obciążenie związane z oczekiwaniem na uruchomienie jest mniejsze i akceptowalne oczekiwanie może być nieco dłuższe, mierzone w milisekundach. Gdy czas oczekiwania jest nieprzewidywalny lub znaczny, użyj System.Threading.Semaphore zamiast tego, co nie powoduje "kręcenia się" wskaźnika oczekiwania. SemaphoreSlim opiera się jak najwięcej na elementach pierwotnych synchronizacji udostępnianych przez środowisko uruchomieniowe języka wspólnego (CLR). Jednak zapewnia również leniwie zainicjowane, oparte na jądrze uchwyty oczekiwania zgodnie z potrzebami, aby obsługiwać oczekiwanie na wiele semaforów. SemaphoreSlim Obsługuje również używanie tokenów anulowania, ale nie obsługuje nazwanych semaforów ani korzystania z uchwytu oczekiwania na synchronizację.

Zarządzanie ograniczonym zasobem

Wątki wchodzą do semafora, wywołując różne metody w zależności od jego typu. W przypadku obiektu System.Threading.Semaphore wywołaj metodę WaitOne (dziedziczoną z WaitHandle klasy). W przypadku obiektu wywołaj metodę SemaphoreSlimSemaphoreSlim.Wait or SemaphoreSlim.WaitAsync . Po powrocie wywołania licznik semafora jest dekrementowany. Gdy wątek żąda dostępu i liczba jest równa zero, wątek jest blokowany. W miarę jak wątki zwalniają semafor, wywołując metodę Semaphore.Release lub SemaphoreSlim.Release, zablokowane wątki mogą wejść. Nie ma gwarantowanej kolejności — takiej jak pierwszy na wejściu, pierwszy na wyjściu (FIFO) lub ostatni na wejściu, pierwszy na wyjściu (LIFO) — decydującej o tym, który z zablokowanych wątków wchodzi następnie do semafora.

Wątek może wielokrotnie wejść do semafora, wywołując metodę obiektu System.Threading.Semaphore lub metodę obiektu WaitOne wielokrotnie. Aby zwolnić semafor, wywołaj metodę Semaphore.Release() lub SemaphoreSlim.Release() tyle razy, ile razy wątek został wprowadzony. Alternatywnie, wywołaj przeciążenie Semaphore.Release(Int32) lub SemaphoreSlim.Release(Int32) i określ liczbę wpisów do zwolnienia.

Semaphores i tożsamość wątków

Dwa typy semaforów nie wymuszają tożsamości wątku na wywołaniach metod WaitOne, Wait, Releasei SemaphoreSlim.Release . Na przykład typowy scenariusz użycia semaforów obejmuje wątek producenta i wątek konsumenta, gdzie jeden wątek zawsze zwiększa liczbę semafora, a drugi ją zmniejsza.

Upewnij się, że wątek nie zwalnia semafora za często. Załóżmy na przykład, że semafor ma maksymalną wartość dwa i że zarówno wątek A, jak i wątek B wchodzą do semafora. Jeśli błąd programowania w wątku B powoduje dwukrotne wywołanie Release , oba wywołania kończą się powodzeniem. Licznik semafora jest pełny, a gdy wątek A ostatecznie wywołuje Release, SemaphoreFullException jest wyrzucany.

Nazwane semafory

System operacyjny Windows umożliwia semaforom posiadanie nazw. Nazwany semafor jest systemowy — po jego utworzeniu jest widoczny dla wszystkich wątków we wszystkich procesach. Nazwane semafory mogą zatem synchronizować działania procesów, a także wątków.

Semaphore Utwórz obiekt reprezentujący nazwany semafor systemowy przy użyciu jednego z konstruktorów, który określa nazwę.

Ważna

Ponieważ nazwane semafory są dostępne w całym systemie, możliwe jest posiadanie wielu Semaphore obiektów reprezentujących ten sam nazwany semafor. Za każdym razem, gdy wywołujesz konstruktor lub Semaphore.OpenExisting metodę, tworzony jest nowy Semaphore obiekt. Określenie tej samej nazwy wielokrotnie tworzy wiele obiektów reprezentujących ten sam semaphor.

Zachowaj ostrożność podczas używania nazwanych semaforów. Ponieważ są systemowe, inny proces, który używa tej samej nazwy, może nieoczekiwanie dostać się do twojego semafora. Złośliwy kod wykonywany na tym samym komputerze może użyć go jako podstawy ataku typu "odmowa usługi".

Użyj zabezpieczeń kontroli dostępu, aby chronić Semaphore obiekt reprezentujący nazwany semafor, najlepiej przy użyciu konstruktora, który określa System.Security.AccessControl.SemaphoreSecurity obiekt. Można również zastosować zabezpieczenia kontroli dostępu przy użyciu metody Semaphore.SetAccessControl, ale pozostawia to okno podatności między momentem utworzenia semafora a momentem jego ochrony. Ochrona semaforów przy użyciu zabezpieczeń kontroli dostępu pomaga zapobiegać złośliwym atakom, ale nie rozwiązuje problemu niezamierzonych kolizji nazw.

Zobacz także