Zmienne warunku
Zmienne warunku są elementami pierwotnymi synchronizacji, które umożliwiają wątkom oczekiwanie na wystąpienie określonego warunku. Zmienne warunku to obiekty w trybie użytkownika, które nie mogą być współużytkowane przez procesy.
Zmienne warunku umożliwiają wątkom niepodzielne zwolnienie blokady i wprowadzenie stanu uśpienia. Mogą być używane z sekcjami krytycznymi lub szczupłymi blokadami czytnika/zapisywania (SRW). Zmienne warunkowe obsługują operacje", które "wznawiają jeden" lub "wznawiają wszystkie" oczekujące wątki. Po przebudzeniu wątku następuje ponowne uzyskanie blokady, która została zwolniona, gdy wątek wszedł w stan uśpienia.
Należy pamiętać, że obiekt wywołujący musi przydzielić strukturę CONDITION_VARIABLE i zainicjować ją przez wywołanie InitializeConditionVariable (aby dynamicznie zainicjować strukturę) lub przypisać stałą CONDITION_VARIABLE_INIT do zmiennej struktury (aby zainicjować strukturę statycznie).
Windows Server 2003 i Windows XP: zmienne warunku nie są obsługiwane.
Poniżej przedstawiono funkcje zmiennych warunku.
Funkcja zmiennej warunku | Opis |
---|---|
initializeConditionVariable | Inicjuje zmienną warunku. |
SleepConditionVariableCS | Uśpienie w określonej zmiennej warunku i zwalnia określoną sekcję krytyczną jako operację niepodzielna. |
SleepConditionVariableSRW | Uśpienie dla określonej zmiennej warunku i zwalnia określoną blokadę SRW jako operację niepodzielna. |
WakeAllConditionVariable | Wznawia wszystkie wątki oczekujące na określoną zmienną warunku. |
WakeConditionVariable | Wznawia oczekiwanie na jeden wątek dla określonej zmiennej warunku. |
Poniższy pseudokod demonstruje typowy wzorzec użycia zmiennych warunku.
CRITICAL_SECTION CritSection;
CONDITION_VARIABLE ConditionVar;
void PerformOperationOnSharedData()
{
EnterCriticalSection(&CritSection);
// Wait until the predicate is TRUE
while( TestPredicate() == FALSE )
{
SleepConditionVariableCS(&ConditionVar, &CritSection, INFINITE);
}
// The data can be changed safely because we own the critical
// section and the predicate is TRUE
ChangeSharedData();
LeaveCriticalSection(&CritSection);
// If necessary, signal the condition variable by calling
// WakeConditionVariable or WakeAllConditionVariable so other
// threads can wake
}
Na przykład w implementacji blokady czytnika/modułu zapisywania funkcja TestPredicate
sprawdzi, czy bieżące żądanie blokady jest zgodne z istniejącymi właścicielami. Jeśli tak jest, uzyskaj blokadę; w przeciwnym razie, sen. Aby uzyskać bardziej szczegółowy przykład, zobacz Using Condition Variables.
Zmienne warunku podlegają fałszywym wznawianiom (niezwiązanym z wyraźnym przebudzeniem) i skradzionym wznawianiu (inny wątek udaje się uruchomić przed wątek obudzony). W związku z tym należy ponownie sprawdzić predykat (zazwyczaj w podczas pętli) po powrocie operacji uśpienia.
Można wznawiać inne wątki przy użyciu WakeConditionVariable lub WakeAllConditionVariable wewnątrz lub na zewnątrz blokady skojarzonej ze zmienną warunku. Zwykle lepiej jest zwolnić blokadę przed przebudzeniem innych wątków, aby zmniejszyć liczbę przełączników kontekstu.
Często wygodne jest używanie więcej niż jednej zmiennej warunku z tą samą blokadą. Na przykład implementacja blokady czytnika/modułu zapisywania może używać jednej sekcji krytycznej, ale oddzielnych zmiennych warunku dla czytelników i składników zapisywania.
Tematy pokrewne