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 de passer à l’état de veille. Ils peuvent être utilisés avec des sections critiques ou des verrous de lecteur/enregistreur (SRW) minces. Les variables de condition prennent en charge les opérations qui « wake one » ou « wake all » des threads en attente. Une fois qu’un thread est réveillé, il récupère à nouveau le verrou qu’il a libéré lorsque le thread est entré en état de veille.
Notez que l’appelant doit allouer une structure CONDITION_VARIABLE et l’initialiser en appelant InitializeConditionVariable (pour initialiser la structure de manière dynamique) ou en affectant la constante CONDITION_VARIABLE_INIT à la variable de structure (pour initialiser la structure statiquement).
Windows Server 2003 et Windows XP : Les variables de 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 pseudo-code 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 TestPredicate
fonction 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, veillez. Pour obtenir un exemple plus détaillé, consultez Utilisation de variables de condition.
Les variables de condition sont soumises à des mises en éveil fallacieuses (celles qui ne sont pas associées à un éveil explicite) et à des éveils 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 une boucle while ) après le retour d’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 seule section critique, mais des variables de condition distinctes pour les lecteurs et les rédacteurs.
Rubriques connexes