Um die Manpage zu zitieren:
Bei Verwendung von Bedingungsvariablen gibt es immer ein boolesches Prädikat mit gemeinsam genutzten Variablen, die jeder Bedingungswartezeit zugeordnet sind. Dies ist der Fall, wenn der Thread fortgesetzt werden soll. Es können falsche Aufweckvorgänge mit den Funktionen pthread_cond_timedwait () oder pthread_cond_wait () auftreten. Da die Rückgabe von pthread_cond_timedwait () oder pthread_cond_wait () nichts über den Wert dieses Prädikats aussagt, sollte das Prädikat bei einer solchen Rückgabe neu bewertet werden.
So pthread_cond_wait
kann zurückkehren , auch wenn Sie es nicht signalisiert haben. Zumindest auf den ersten Blick scheint das ziemlich grausam. Es wäre wie eine Funktion, die zufällig den falschen Wert oder zufällig zurückgegeben hat, bevor sie tatsächlich eine richtige return-Anweisung erreicht hat. Es scheint ein großer Fehler zu sein. Aber die Tatsache, dass sie sich dafür entschieden haben, dies auf der Manpage zu dokumentieren, anstatt es zu korrigieren, scheint darauf hinzudeuten, dass es einen legitimen Grund gibt, warum pthread_cond_wait
sie falsch aufwachen. Vermutlich hat die Funktionsweise etwas Eigenes, das dazu beiträgt, dass dem nicht geholfen werden kann. Die Frage ist was.
Warum ist pthread_cond_wait
spuriously zurückkehren? Warum kann es nicht garantieren, dass es nur aufwacht, wenn es richtig signalisiert wurde? Kann jemand den Grund für sein falsches Verhalten erklären?
pthread_cond_(timed)wait
: "Wenn ein Signal geliefert wird ... setzt der Thread das Warten auf die Bedingungsvariable fort, als ob es wäre nicht unterbrochen, oder es wird aufgrund eines falschen Aufwachens Null zurückgegeben ". Andere Sperrfunktionen zeigen an,EINTR
wenn sie durch ein Signal unterbrochen werden (z. B.read
) oder fortgesetzt werden müssen (zpthread_mutex_lock
. B. ). Wenn es also keine anderen Gründe für ein falsches Aufwachen gäbe,pthread_cond_wait
hätte dies wie einer der beiden definiert werden können.Antworten:
Die folgende Erklärung wird von David R. Butenhof in "Programmieren mit POSIX-Threads" (S. 80) gegeben:
In der folgenden Diskussion zu comp.programming.threads erweitert er das Denken hinter dem Design:
quelle
Es gibt mindestens zwei Dinge, die "falsches Aufwachen" bedeuten könnte:
pthread_cond_wait
kann vom Anruf zurückkehren, obwohl kein Anruf anpthread_call_signal
oderpthread_cond_broadcast
unter der Bedingung aufgetreten ist.pthread_cond_wait
aufgrund eines Aufrufs vonpthread_cond_signal
oder in zurückgegeben wirdpthread_cond_broadcast
, wird jedoch nach dem erneuten Abrufen des Mutex als nicht mehr wahr eingestuft.Der letztere Fall kann jedoch auch dann auftreten, wenn die Implementierung der Bedingungsvariablen den ersteren Fall nicht zulässt. Betrachten Sie eine Producer-Consumer-Warteschlange und drei Threads.
pthread_cond_wait
und Blöcken in dem auf Signal / Broadcast wartenden Anruf überprüft wird .Da Sie das Prädikat bereits immer unter einer Schleife überprüfen müssen, spielt es keine Rolle, ob die zugrunde liegenden Bedingungsvariablen andere Arten von falschen Aufwecken aufweisen können.
quelle
pthread_cond_signal/broadcast
sollst und dies nicht kannst, bis der Mutex durch einen Anruf entsperrt wirdpthread_cond_wait
.Der Abschnitt "Mehrfaches Erwachen durch Bedingungssignal" in pthread_cond_signal enthält eine Beispielimplementierung von pthread_cond_wait und pthread_cond_signal, die falsche Wakekups beinhaltet.
quelle
Obwohl ich nicht denke, dass dies zum Zeitpunkt des Entwurfs in Betracht gezogen wurde, gibt es hier einen tatsächlichen technischen Grund: In Kombination mit der Thread-Löschung gibt es Bedingungen, unter denen die Option, "falsch" aufzuwachen, absolut notwendig sein kann, zumindest wenn Sie dies nicht tun sind bereit, sehr, sehr starke Einschränkungen für die möglichen Implementierungsstrategien aufzuerlegen.
Das Hauptproblem besteht darin, dass, wenn ein Thread beim Blockieren auf die Löschung einwirkt
pthread_cond_wait
, die Nebenwirkungen so sein müssen, als hätte er kein Signal für die Bedingungsvariable verbraucht. Es ist jedoch schwierig (und sehr einschränkend) sicherzustellen, dass Sie noch kein Signal verbraucht haben, wenn Sie mit der Löschung beginnen. In diesem Stadium ist es möglicherweise unmöglich, das Signal erneut in die Bedingungsvariable zu "posten", da dies möglich ist in einer Situation sein, in der der Anrufer vonpthread_cond_signal
bereits berechtigt ist, die Kondvar zerstört und die Erinnerung, in der sie sich befand, freigegeben zu haben.Die Berücksichtigung von falschem Wake macht es Ihnen leicht. Anstatt weiterhin auf die Stornierung zu reagieren, wenn sie eingeht, während sie für eine Bedingungsvariable blockiert ist, können Sie stattdessen ein falsches Wake deklarieren, wenn Sie möglicherweise bereits ein Signal verbraucht haben (oder wenn Sie faul sein möchten, egal was passiert). und mit Erfolg zurückkehren. Dies stört den Vorgang der Stornierung überhaupt nicht, da ein korrekter Anrufer beim nächsten Schleifen und
pthread_cond_wait
erneuten Anrufen einfach auf die anstehende Stornierung reagiert .quelle