pthread_cond_init, pthread_cond_destroy, pthread_cond_signal,
pthread_cond_broadcast, pthread_cond_wait, pthread_cond_timedwait -
Opérations sur les conditions
#include <pthread.h>
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t
* cond_attr);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t
* mutex);
int pthread_cond_timedwait(pthread_cond_t *cond,
pthread_mutex_t * mutex, const struct timespec
*abstime );
int pthread_cond_destroy(pthread_cond_t *cond);
Une condition (abréviation pour « variable
condition ») est un mécanisme de synchronisation
permettant à un thread de suspendre son exécution jusqu'à
ce qu'une certaine condition (un prédicat) sur des données
partagées soit vérifiée. Les opérations
fondamentales sur les conditions sont : signaler la condition (quand le
prédicat devient vrai) et attendre la condition en suspendant
l'exécution du thread jusqu'à ce qu'un autre thread signale la
condition.
Une variable condition doit toujours être associée à un
mutex, pour éviter une condition concurrente où un thread se
prépare à attendre une condition et un autre thread signale la
condition juste avant que le premier n'attende réellement.
pthread_cond_init() initialise la variable condition
cond, en
utilisant les attributs de condition spécifiés par
cond_attr, ou les attributs par défaut si
cond_attr vaut
NULL. L'implémentation LinuxThreads ne supporte aucun attribut de
condition, aussi le paramètre
cond_attr est pour l'instant
ignoré.
Les variables de type
pthread_cond_t peuvent également être
statiquement initialisées, en utilisant la constante
PTHREAD_COND_INITIALIZER.
pthread_cond_signal() relance l'un des threads attendant la variable
condition
cond. S'il n'existe aucun thread répondant à ce
critère, rien ne se produit. Si plusieurs threads attendent sur
cond, seul l'un d'entre eux sera relancé, mais il est impossible
de savoir lequel.
pthread_cond_broadcast() relance tous les threads attendant sur la
variable condition
cond. Rien ne se passe s'il n'y a aucun thread
attendant sur
cond.
pthread_cond_wait() déverrouille atomiquement le
mutex
(comme
pthread_unlock_mutex()) et attend que la variable condition
cond soit signalée. L'exécution du thread est suspendue
et ne consomme pas de temps CPU jusqu'à ce que la variable condition
soit signalée. Le
mutex doit être verrouillé par
le thread appelant à l'entrée de
pthread_cond_wait().
Avant de rendre la main au thread appelant,
pthread_cond_wait()
reverrouille
mutex (comme
pthread_lock_mutex()).
Le déverrouillage du mutex et la suspension de l'exécution sur la
variable condition sont liés atomiquement. Donc, si tous les threads
verrouillent le mutex avant de signaler la condition, il est garanti que la
condition ne peut être signalée (et donc ignorée) entre
le moment où un thread verrouille le mutex et le moment où il
attend sur la variable condition.
pthread_cond_timedwait() déverrouille le
mutex et attend
sur
cond, en liant atomiquement ces deux étapes, comme le fait
pthread_cond_wait(), cependant l'attente est bornée
temporellement. Si
cond n'a pas été signalée
après la période spécifiée par
abstime, le
mutex
mutex est reverrouillé et
pthread_cond_timedwait()
rend la main avec l'erreur
ETIMEDOUT. Le paramètre
abstime spécifie un temps absolu, avec la même origine
que
time(2) et
gettimeofday(2) : un
abstime de 0
correspond à 00:00:00 GMT, le 1er Janvier 1970.
pthread_cond_destroy() détruit une variable condition,
libérant les ressources qu'elle possède. Aucun thread ne doit
attendre sur la condition à l'entrée de
pthread_cond_destroy(). Dans l'implémentation LinuxThreads,
aucune ressource ne peut être associée à une variable
condition, aussi
pthread_cond_destroy() ne fait en fait rien d'autre
que vérifier qu'aucun thread n'attend la condition.
pthread_cond_wait() et
pthread_cond_timedwait() sont des points
d'annulation. Si un thread est annulé alors qu'il est suspendu dans
l'une de ces fonctions, son exécution reprend immédiatement,
reverrouillant le paramètre
mutex à
pthread_cond_wait() et
pthread_cond_timedwait(), et
exécute finalement l'annulation. Aussi, les gestionnaires d'annulation
sont assurés que
mutex est verrouillé lorsqu'ils sont
exécutés.
Ces fonctions ne sont pas fiables par rapport aux signaux asynchrones et ne
doivent donc pas être utilisées dans des gestionnaires de
signaux [NdT : sous peine de perdre leur propriété
d'atomicité]. En particulier, appeler
pthread_cond_signal() ou
pthread_cond_broadcast() dans un gestionnaire de signal peut placer le
thread appelant dans une situation de blocage définitif.
Toutes ces fonctions renvoient 0 en cas de succès et un code d'erreur non
nul en cas de problème.
pthread_cond_init(),
pthread_cond_signal(),
pthread_cond_broadcast() et
pthread_cond_wait() ne renvoient
jamais de code d'erreur.
La fonction
pthread_cond_timedwait() renvoie l'un des codes d'erreur
suivants en cas de problème :
- ETIMEDOUT
- La variable condition n'a pas reçu de signal avant
le délai spécifié par abstime.
- EINTR
-
pthread_cond_timedwait() a été
interrompu par un signal.
La fonction
pthread_cond_destroy() renvoie le code d'erreur suivant en
cas de problème :
- EBUSY
- Il existe des threads attendant cond.
Xavier Leroy <
[email protected]>
pthread_condattr_init(3),
pthread_mutex_lock(3),
pthread_mutex_unlock(3),
gettimeofday(2),
nanosleep(2)
Considérons deux variables globales partagées
x et
y, protégées par le mutex
mut, et une variable
condition
cond pour signaler que
x devient plus grand que
y.
int x,y; pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
Attendre que
x devienne plus grand que
y se réalise de la
manière suivante :
pthread_mutex_lock(&mut); while (x <= y) { pthread_cond_wait(&cond, &mut); } /* operate on x and y */ pthread_mutex_unlock(&mut);
Les modifications de
x et
y qui peuvent rendre
x plus grand
que
y doivent signaler la condition si nécessaire :
pthread_mutex_lock(&mut); /* modify x and y */ if (x > y) pthread_cond_broadcast(&cond); pthread_mutex_unlock(&mut);
S'il peut être prouvé qu'au plus un thread en attente
nécessite d'être réveillé (par exemple, s'il n'y a
que deux threads communiquant via
x et
y),
pthread_cond_signal() peut être utilisé en tant
qu'alternative efficace à
pthread_cond_broadcast(). En cas de
doute, utilisez
pthread_cond_broadcast().
Pour attendre que
x devienne plus grand que
y avec un délai
de 5 secondes, faîtes :
struct timeval now; struct timespec timeout; int retcode;
pthread_mutex_lock(&mut); gettimeofday(&now); timeout.tv_sec = now.tv_sec + 5; timeout.tv_nsec = now.tv_usec * 1000; retcode = 0; while (x <= y && retcode != ETIMEDOUT) { retcode = pthread_cond_timedwait(&cond, &mut, &timeout); } if (retcode == ETIMEDOUT) { /* timeout occurred */ } else { /* operate on x and y */ } pthread_mutex_unlock(&mut);
La traduction française de cette page de manuel a été
créée par Gérard Delafond <
[email protected]>,
Christophe Blaess <
[email protected]>, Thierry Vignaud
<
[email protected]>, Alain Portal <
[email protected]>,
Denis Barbier <
[email protected]>, Nicolas François
<
[email protected]>, Florentin Duneau
<
[email protected]>, Thomas Blein <
[email protected]> et David
Prévot <
[email protected]>
Cette traduction est une documentation libre ; veuillez vous reporter
à la
GNU
General Public License version 3 concernant les conditions de copie
et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.
Si vous découvrez un bogue dans la traduction de cette page de manuel,
veuillez envoyer un message à
[email protected]