Переменные условия
Переменные условия — это примитивы синхронизации, которые позволяют потокам ожидать выполнения определенного условия. Переменные условия — это объекты пользовательского режима, которые нельзя совместно использовать в процессах.
Переменные условия позволяют потокам атомарно освобождать блокировку и переходить в спящее состояние. Их можно использовать с критически важными разделами или с тонкими блоками чтения и записи (SRW). Переменные условия поддерживают операции , которые "пробуждение одного" или "пробуждение всех" ожидающих потоков. После пробуждения поток повторно получает блокировку, освобожденную при входе потока в спящее состояние.
Обратите внимание, что вызывающий объект должен выделить CONDITION_VARIABLE структуру и инициализировать ее путем вызова Метода InitializeConditionVariable (для динамической инициализации структуры) или назначения константы CONDITION_VARIABLE_INIT переменной структуры (для статической инициализации структуры).
Windows Server 2003 и Windows XP: Переменные условия не поддерживаются.
Ниже приведены функции переменной условия.
Функция переменной условия | Описание |
---|---|
InitializeConditionVariable | Инициализирует переменную условия. |
SleepConditionVariableCS | Переходит в спящий режим для указанной переменной условия и освобождает указанный критический раздел как атомарную операцию. |
SleepConditionVariableSRW | Переходит в спящий режим для указанной переменной условия и освобождает указанную блокировку SRW как атомарную операцию. |
WakeAllConditionVariable | Пробуждение всех потоков, ожидающих указанной переменной условия. |
WakeConditionVariable | Пробуждает один поток, ожидающий указанной переменной условия. |
Следующий псевдокод демонстрирует типичный шаблон использования переменных условий.
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
}
Например, в реализации блокировки чтения или записи функция проверяет совместимость TestPredicate
текущего запроса блокировки с существующими владельцами. Если это так, получите блокировку; в противном случае — спящий режим. Более подробный пример см. в разделе Использование переменных условия.
Переменные условий подвержены фиктивным пробуждениям (не связанным с явным пробуждением) и украденным пробуждениям (другой поток запускается до пробуждения потока). Поэтому после возврата операции спящего режима необходимо повторно проверить предикат (обычно в цикле while ).
Другие потоки можно разбудить с помощью WakeConditionVariable или WakeAllConditionVariable внутри или за пределами блокировки, связанной с переменной условия. Обычно лучше освободить блокировку перед пробуждением других потоков, чтобы уменьшить количество переключений контекста.
Часто удобно использовать несколько переменных условия с одной блокировкой. Например, реализация блокировки чтения и записи может использовать один критически важный раздел, но отдельные переменные условия для читателей и модулей записи.
Связанные темы