C'est juste la façon dont les variables de condition sont (ou étaient à l'origine) implémentées.
Le mutex est utilisé pour protéger la variable de condition elle-même . C'est pourquoi vous devez le verrouiller avant d'attendre.
L'attente déverrouillera "atomiquement" le mutex, permettant aux autres d'accéder à la variable de condition (pour la signalisation). Ensuite, lorsque la variable de condition est signalée ou diffusée vers, un ou plusieurs threads de la liste d'attente seront réveillés et le mutex sera à nouveau verrouillé par magie pour ce thread.
Vous voyez généralement l'opération suivante avec des variables de condition, illustrant leur fonctionnement. L'exemple suivant est un thread de travail qui reçoit du travail via un signal à une variable de condition.
thread:
initialise.
lock mutex.
while thread not told to stop working:
wait on condvar using mutex.
if work is available to be done:
do the work.
unlock mutex.
clean up.
exit thread.
Le travail se fait au sein de cette boucle à condition qu'il y en ait de disponible au retour de l'attente. Lorsque le thread a été marqué pour arrêter de faire le travail (généralement par un autre thread définissant la condition de sortie puis coupant la variable de condition pour réveiller ce thread), la boucle se terminera, le mutex sera déverrouillé et ce thread se fermera.
Le code ci-dessus est un modèle à consommateur unique car le mutex reste verrouillé pendant que le travail est en cours. Pour une variante multi-consommateurs, vous pouvez utiliser, à titre d' exemple :
thread:
initialise.
lock mutex.
while thread not told to stop working:
wait on condvar using mutex.
if work is available to be done:
copy work to thread local storage.
unlock mutex.
do the work.
lock mutex.
unlock mutex.
clean up.
exit thread.
ce qui permet à d'autres consommateurs de recevoir du travail pendant que celui-ci travaille.
La variable de condition vous libère du fardeau d'interroger une condition au lieu de permettre à un autre thread de vous avertir lorsque quelque chose doit se produire. Un autre thread peut dire que le thread qui fonctionne est disponible comme suit:
lock mutex.
flag work as available.
signal condition variable.
unlock mutex.
La grande majorité de ce que l'on appelle souvent à tort des réveils parasites était généralement toujours parce que plusieurs threads avaient été signalés dans leur pthread_cond_wait
appel (diffusion), on revenait avec le mutex, faisait le travail, puis attendait à nouveau.
Ensuite, le deuxième fil signalé pouvait sortir lorsqu'il n'y avait pas de travail à faire. Vous deviez donc avoir une variable supplémentaire indiquant que le travail devait être fait (cela était intrinsèquement protégé contre le mutex avec la paire condvar / mutex ici - d'autres threads devaient cependant verrouiller le mutex avant de le modifier).
Il était techniquement possible pour un thread de revenir d'une condition d'attente sans être lancé par un autre processus (il s'agit d'un véritable faux réveil) mais, au cours de toutes mes années de travail sur pthreads, à la fois dans le développement / service du code et en tant qu'utilisateur d’entre eux, je n’en ai jamais reçu un seul. Peut-être était-ce simplement parce que HP avait une implémentation décente :-)
Dans tous les cas, le même code qui a traité le cas erroné a également géré les véritables réveils parasites, car l'indicateur de travail disponible ne serait pas défini pour ceux-ci.