Поделиться через


Переменные условия

Переменные условия — это примитивы синхронизации, которые позволяют потокам ожидать выполнения определенного условия. Переменные условия — это объекты пользовательского режима, которые нельзя совместно использовать в процессах.

Переменные условия позволяют потокам атомарно освобождать блокировку и переходить в спящее состояние. Их можно использовать с критически важными разделами или с тонкими блоками чтения и записи (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 внутри или за пределами блокировки, связанной с переменной условия. Обычно лучше освободить блокировку перед пробуждением других потоков, чтобы уменьшить количество переключений контекста.

Часто удобно использовать несколько переменных условия с одной блокировкой. Например, реализация блокировки чтения и записи может использовать один критически важный раздел, но отдельные переменные условия для читателей и модулей записи.

Использование переменных условия