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);
45
demandé sur Emiliano 2009-07-16 13:17:09

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.

43
répondu Chris Lu 2011-01-27 20:47:37

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.

15
répondu Steve Jessop 2012-06-03 10:03:29