Pour citer la page de manuel:
Lors de l'utilisation de variables de condition, il existe toujours un prédicat booléen impliquant des variables partagées associées à chaque condition d'attente qui est vrai si le thread doit continuer. Des réveils parasites des fonctions pthread_cond_timedwait () ou pthread_cond_wait () peuvent se produire. Puisque le retour de pthread_cond_timedwait () ou pthread_cond_wait () n'implique rien sur la valeur de ce prédicat, le prédicat doit être réévalué lors d'un tel retour.
Donc, pthread_cond_wait
peut revenir même si vous ne l'avez pas signalé. À première vue du moins, cela semble assez atroce. Ce serait comme une fonction qui retournait aléatoirement la mauvaise valeur ou renvoyée aléatoirement avant d'atteindre réellement une instruction de retour correcte. Cela semble être un bug majeur. Mais le fait qu'ils aient choisi de documenter cela dans la page de manuel plutôt que de corriger cela semble indiquer qu'il y a une raison légitime pour laquelle pthread_cond_wait
finit par se réveiller de manière indue. Vraisemblablement, il y a quelque chose d'intrinsèque dans son fonctionnement qui fait que cela ne peut pas être aidé. La question est de savoir quoi.
Pourquoi ne pthread_cond_wait
revenir spuriously? Pourquoi ne peut-il pas garantir qu'il ne se réveillera que lorsqu'il aura été correctement signalé? Quelqu'un peut-il expliquer la raison de son comportement faux?
pthread_cond_(timed)wait
: "Si un signal est délivré ... le thread recommence à attendre la variable de condition comme si c'était pas interrompu, ou il doit retourner zéro en raison d'un faux réveil ". D'autres fonctions de blocage indiquentEINTR
lorsqu'elles sont interrompues par un signal (par exempleread
), ou doivent reprendre (par exemplepthread_mutex_lock
). Donc, s'il n'y avait pas d'autres raisons pour un faux réveil, celapthread_cond_wait
aurait pu être défini comme l'un ou l'autre.Réponses:
L'explication suivante est donnée par David R. Butenhof dans "Programming with POSIX Threads" (p. 80):
Dans la discussion comp.programming.threads suivante , il développe la réflexion derrière la conception:
la source
Il y a au moins deux choses que pourrait signifier un `` faux réveil '':
pthread_cond_wait
peut revenir de l'appel même si aucun appel verspthread_call_signal
oupthread_cond_broadcast
sur la condition ne s'est produit.pthread_cond_wait
retours en raison d'un appel àpthread_cond_signal
oupthread_cond_broadcast
, cependant, après la réacquisition du mutex, le prédicat sous-jacent s'avère ne plus être vrai.Mais ce dernier cas peut se produire même si l'implémentation de la variable de condition ne permet pas le premier cas. Considérez une file d'attente de consommateurs de producteurs et trois threads.
pthread_cond_wait
et les blocs dans l'appel en attente de signal / diffusion.Donc, comme vous devez déjà toujours vérifier le prédicat sous une boucle, cela ne fait aucune différence si les variables de condition sous-jacentes peuvent avoir d'autres types de réveils parasites.
la source
pthread_cond_signal/broadcast
et vous ne pourrez pas le faire tant que le mutex ne sera pas déverrouillé en appelantpthread_cond_wait
.La section "Réveils multiples par signal de condition" dans pthread_cond_signal a un exemple d'implémentation de pthread_cond_wait et pthread_cond_signal qui implique des réveils parasites.
la source
Bien que je ne pense pas que cela ait été envisagé au moment de la conception, voici une raison technique réelle: en combinaison avec l'annulation de thread, il existe des conditions dans lesquelles prendre l'option de se réveiller "faussement" peut être absolument nécessaire, du moins à moins que vous sont disposés à imposer des contraintes très très fortes sur les types de stratégies de mise en œuvre possibles.
Le problème clé est que, si un thread agit sur l'annulation alors qu'il est bloqué
pthread_cond_wait
, les effets secondaires doivent être comme s'il ne consommait aucun signal sur la variable de condition. Cependant, il est difficile (et très contraignant) de s'assurer que vous n'avez pas déjà consommé un signal lorsque vous commencez à agir sur l'annulation, et à ce stade, il peut être impossible de «re-poster» le signal dans la variable de condition, car vous pouvez être dans une situation où l'appelant depthread_cond_signal
est déjà justifié d'avoir détruit le condvar et libéré la mémoire dans laquelle il résidait.La tolérance pour un faux réveil vous permet de sortir facilement. Au lieu de continuer à agir sur l'annulation lorsqu'il arrive alors qu'il est bloqué sur une variable de condition, si vous avez peut-être déjà consommé un signal (ou si vous voulez être paresseux, quoi qu'il arrive), vous pouvez déclarer qu'un faux réveil s'est produit à la place, et revenez avec succès. Cela n'interfère pas du tout avec l'opération d'annulation, car un appelant correct agira simplement sur l'annulation en attente la prochaine fois qu'il bouclera et appellera à
pthread_cond_wait
nouveau.la source