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


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

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

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

Переменные условий подвержены спровождительным пробуждениям (не связанным с явным пробуждением) и украденным пробуждением (другой поток управляет выполнением до проснувшегося потока). Поэтому необходимо повторно проверить предикат (обычно в во время цикла) после возврата операции спящего режима.

Вы можете пробуждение других потоков с помощью WakeConditionVariable или WakeAllConditionVariable внутри или за пределами блокировки, связанной с переменной условия. Как правило, лучше освободить блокировку перед пробуждением других потоков, чтобы уменьшить количество переключений контекста.

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

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