Partilhar via


Variáveis de condição

As variáveis de condição são primitivas de sincronização que permitem que os threads esperem até que uma determinada condição ocorra. As variáveis de condição são objetos de modo de usuário que não podem ser compartilhados entre processos.

As variáveis de condição permitem que os threads liberem atomicamente um bloqueio e entrem no estado de suspensão. Eles podem ser usados com seções críticas ou fechaduras finas de leitor/gravador (SRW). As variáveis de condição suportam operações que "acordam um" ou "acordam todos" os threads de espera. Depois que um fio é acordado, ele readquire o bloqueio que liberou quando o fio entrou no estado de suspensão.

Observe que o chamador deve alocar uma estrutura de CONDITION_VARIABLE e inicializá-la chamando InitializeConditionVariable (para inicializar a estrutura dinamicamente) ou atribuir o CONDITION_VARIABLE_INIT constante à variável de estrutura (para inicializar a estrutura estaticamente).

Windows Server 2003 e Windows XP: variáveis de condição não são suportadas.

A seguir estão as funções da variável de condição.

Função variável de condição Descrição
InitializeConditionVariable Inicializa uma variável de condição.
SleepConditionVariableCS Suspende na variável de condição especificada e libera a seção crítica especificada como uma operação atômica.
SleepConditionVariableSRW Suspende na variável de condição especificada e libera o bloqueio SRW especificado como uma operação atômica.
WakeAllConditionVariable Desperta todos os threads aguardando na variável de condição especificada.
WakeConditionVariable Ativa um único thread aguardando na variável de condição especificada.

 

O pseudocódigo a seguir demonstra o padrão de uso típico de variáveis de condição.

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
}

Por exemplo, em uma implementação de um bloqueio de leitor/gravador, a função TestPredicate verificaria se a solicitação de bloqueio atual é compatível com os proprietários existentes. Se estiver, adquira a fechadura; caso contrário, durma. Para obter um exemplo mais detalhado, consulte Usando variáveis de condição.

As variáveis de condição estão sujeitas a despertares espúrios (aqueles não associados a um despertar explícito) e despertares roubados (outro fio consegue correr antes do fio acordado). Portanto, você deve verificar novamente um predicado (normalmente em um enquanto loop) depois que uma operação de suspensão retorna.

Você pode ativar outros threads usando WakeConditionVariable ou WakeAllConditionVariable dentro ou fora do bloqueio associado à variável de condição. Normalmente, é melhor liberar o bloqueio antes de acordar outros threads para reduzir o número de opções de contexto.

Muitas vezes, é conveniente usar mais de uma variável de condição com o mesmo bloqueio. Por exemplo, uma implementação de um bloqueio de leitor/gravador pode usar uma única seção crítica, mas variáveis de condição separadas para leitores e gravadores.

Usando variáveis de condição