Pthread et conditions d'attente
J'apprends les conditions de pthread et d'attente. Pour autant que je sache, un fil d'attente typique est comme ceci:
pthread_mutex_lock(&m);
while(!condition)
pthread_cond_wait(&cond, &m);
// Thread stuff here
pthread_mutex_unlock(&m);
Ce que je ne peux pas comprendre, c'est pourquoi la ligne while(!condition)
est nécessaire, même si j'utilise pthread_cond_signal()
réveiller le fil.
Je peux comprendre que si j'utilise pthread_cond_broadcast()
j'ai besoin de tester la condition, car je réveille Tous les threads en attente et l'un d'eux peut rendre la condition fausse à nouveau avant de déverrouiller le mutex (et ainsi transférer l'exécution à un autre thread réveillé qui ne devrait pas s'exécuter à ce stade).
Mais si j'utilise pthread_cond_signal()
je me réveille juste un thread afin que la condition doit être vrai. Donc, le code pourrait ressembler à ceci:
pthread_mutex_lock(&m);
pthread_cond_wait(&cond, &m);
// Thread stuff here
pthread_mutex_unlock(&m);
J'ai lu quelque chose sur les signaux parasites qui peuvent arriver. Est-ce (et seulement cela) la raison? Pourquoi devrais-je avoir des singnals faux? Ou il y a autre chose que je ne comprends pas?
Je suppose que le code du signal est comme ceci:
pthread_mutex_lock(&m);
condition = true;
pthread_cond_signal(&cond); // Should wake up *one* thread
pthread_mutex_unlock(&m);
2 réponses
La vraie raison pour laquelle vous devriez mettre pthread_cond_wait dans une boucle while n'est pas à cause d'un réveil parasite. Même si votre variable de condition n'avait pas de réveil parasite, vous auriez toujours besoin de la boucle pour attraper un type d'erreur commun. Pourquoi? Considérez ce qui peut arriver si plusieurs threads attendent dans la même condition:
Thread 1 Thread 2 Thread 3
check condition (fails)
(in cond_wait) unlock mutex
(in cond_wait) wait
lock mutex
set condition
signal condvar
unlock mutex
lock mutex
check condition (succeeds)
do stuff
unset condition
unlock mutex
(in cond_wait) wake up
(in cond_wait) lock mutex
<thread is awake, but condition
is unset>
Le problème ici est que le thread doit libérer le mutex avant d'attendre, permettant potentiellement à un autre thread de "voler" tout ce que ce thread attendait. À moins qu'il est garanti qu'un seul thread peut attendre sur cette condition, il est incorrect de supposer que la condition est valide lorsqu'un thread se réveille.
Supposons que vous ne Vérifiez pas la condition. Ensuite, vous ne pouvez généralement pas éviter la mauvaise chose suivante (au moins, vous ne pouvez pas l'éviter dans une ligne de code):
Sender Receiver
locks mutex
sets condition
signals condvar, but nothing
is waiting so has no effect
releases mutex
locks mutex
waits. Forever.
Bien Sûr, votre deuxième exemple de code pourrait éviter cela en faisant:
pthread_mutex_lock(&m);
if (!condition) pthread_cond_wait(&cond, &m);
// Thread stuff here
pthread_mutex_unlock(&m);
Alors il serait certainement le cas que s'il n'y a jamais qu'un seul récepteur, et si cond_signal
était la seule chose qui pourrait le réveiller, alors il ne se réveillerait jamais que lorsque la condition était définie et n'aurait donc pas besoin d'une boucle. nos couvre pourquoi le deuxième " si " n'est pas vrai.