Variáveis de condição

As variáveis de condição são primitivas de sincronização que permitem que os threads aguardem até que ocorra uma condição específica. 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 insiram o estado de suspensão. Eles podem ser usados com seções críticas ou bloqueios de leitor/gravador fino (SRW). As variáveis de condição dão suporte a operações que "ativam um" ou "ativam todos" threads de espera. Depois que um thread é acordado, ele adquire novamente o bloqueio liberado quando o thread entrou no estado de suspensão.

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

Windows Server 2003 e Windows XP: Não há suporte para variáveis de condição.

Veja a seguir as funções de variável de condição.

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

 

O pseudocódigo a seguir demonstra o padrão de uso típico das 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 TestPredicate função verificaria se a solicitação de bloqueio atual é compatível com os proprietários existentes. Se for, adquira o bloqueio; 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 ativações espúrias (aquelas não associadas a uma ativação explícita) e ativações roubadas (outro thread consegue ser executado antes do thread acordado). Portanto, você deve verificar novamente um predicado (normalmente em um loop de tempo ) após o retorno de uma operação de suspensão.

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

Geralmente, é 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