Condition Variables
Les variables de condition sont des primitives de synchronisation qui permettent aux threads d’attendre qu’une condition particulière se produise. Les variables de condition sont des objets en mode utilisateur qui ne peuvent pas être partagés entre les processus.
Les variables de condition permettent aux threads de libérer atomiquement un verrou et d’entrer l’état de veille. Ils peuvent être utilisés avec des sections critiques ou des verrous lecteur/enregistreur (SRW). Les variables de condition prennent en charge les opérations « wake one » ou « wake all » en attente de threads. Une fois qu’un thread est réveillé, il acquiert à nouveau le verrou qu’il a libéré lorsque le thread est entré dans l’état de veille.
Notez que l’appelant doit allouer une structure CONDITION_VARIABLE et l’initialiser en appelant InitializeConditionVariable (pour initialiser la structure dynamiquement) ou affecter la constante CONDITION_VARIABLE_INIT à la variable de structure (pour initialiser la structure statiquement).
les variables Windows Server 2003 et Windows XP : variables condition ne sont pas prises en charge.
Voici les fonctions de variable de condition.
Fonction de variable de condition | Description |
---|---|
InitializeConditionVariable | Initialise une variable de condition. |
SleepConditionVariableCS | Veille sur la variable de condition spécifiée et libère la section critique spécifiée en tant qu’opération atomique. |
sleepConditionVariableSRW | Veille sur la variable de condition spécifiée et libère le verrou SRW spécifié en tant qu’opération atomique. |
WakeAllConditionVariable | Réveille tous les threads en attente sur la variable de condition spécifiée. |
wakeConditionVariable | Réveille un thread unique en attente sur la variable de condition spécifiée. |
Le pseudocode suivant illustre le modèle d’utilisation classique des variables de condition.
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
}
Par exemple, dans une implémentation d’un verrou lecteur/enregistreur, la fonction TestPredicate
vérifie que la demande de verrouillage actuelle est compatible avec les propriétaires existants. Si c’est le cas, acquérir le verrou ; sinon, dormir. Pour obtenir un exemple plus détaillé, consultez Utilisation de variables de condition.
Les variables de condition sont sujettes à de fausses sorties de veille (celles qui ne sont pas associées à un éveil explicite) et à des wakeups volés (un autre thread parvient à s’exécuter avant le thread réveillé). Par conséquent, vous devez revérifier un prédicat (généralement dans un pendant boucle) après une opération de veille.
Vous pouvez réveiller d’autres threads à l’aide de WakeConditionVariable ou WakeAllConditionVariable à l’intérieur ou à l’extérieur du verrou associé à la variable de condition. Il est généralement préférable de libérer le verrou avant de réveiller d’autres threads pour réduire le nombre de commutateurs de contexte.
Il est souvent pratique d’utiliser plusieurs variables de condition avec le même verrou. Par exemple, une implémentation d’un verrou lecteur/enregistreur peut utiliser une section critique unique, mais des variables de condition distinctes pour les lecteurs et les enregistreurs.
Rubriques connexes