Es ist nur die Art und Weise, wie Bedingungsvariablen implementiert werden (oder ursprünglich).
Der Mutex wird verwendet, um die Bedingungsvariable selbst zu schützen . Deshalb muss es gesperrt sein, bevor Sie warten.
Durch das Warten wird der Mutex "atomar" entsperrt, sodass andere auf die Bedingungsvariable zugreifen können (zur Signalisierung). Wenn dann die Bedingungsvariable signalisiert oder gesendet wird, werden einer oder mehrere der Threads auf der Warteliste aufgeweckt und der Mutex wird für diesen Thread wieder magisch gesperrt.
In der Regel wird die folgende Operation mit Bedingungsvariablen angezeigt, die ihre Funktionsweise veranschaulicht. Das folgende Beispiel ist ein Arbeitsthread, der über ein Signal an eine Bedingungsvariable Arbeit erhält.
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.
Die Arbeit wird innerhalb dieser Schleife erledigt, vorausgesetzt, es sind einige verfügbar, wenn die Wartezeit zurückkehrt. Wenn der Thread markiert wurde, um die Arbeit zu beenden (normalerweise durch einen anderen Thread, der die Beendigungsbedingung festlegt und dann die Bedingungsvariable aufruft, um diesen Thread aufzuwecken), wird die Schleife beendet, der Mutex wird entsperrt und dieser Thread wird beendet.
Der obige Code ist ein Einzelverbrauchermodell, da der Mutex während der Arbeit gesperrt bleibt. Für eine Multi-Consumer-Variante können Sie als Beispiel Folgendes verwenden :
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.
Dies ermöglicht anderen Verbrauchern, Arbeit zu erhalten, während dieser Arbeit erledigt.
Die Bedingungsvariable entlastet Sie von der Last, eine Bedingung abzufragen, anstatt dass ein anderer Thread Sie benachrichtigt, wenn etwas passieren muss. Ein anderer Thread kann diesem Thread mitteilen, dass diese Arbeit wie folgt verfügbar ist:
lock mutex.
flag work as available.
signal condition variable.
unlock mutex.
Die überwiegende Mehrheit der häufig fälschlicherweise als unechte Aufweckvorgänge bezeichneten Probleme war im Allgemeinen immer darauf zurückzuführen, dass innerhalb ihres pthread_cond_wait
Anrufs (Broadcast) mehrere Threads signalisiert wurden. Man kehrte mit dem Mutex zurück, erledigte die Arbeit und wartete erneut.
Dann konnte der zweite signalisierte Thread herauskommen, wenn keine Arbeit zu erledigen war. Sie mussten also eine zusätzliche Variable haben, die angibt, dass die Arbeit erledigt werden soll (dies war von Natur aus mutexgeschützt mit dem Condvar / Mutex-Paar hier - andere Threads mussten den Mutex sperren, bevor er geändert wurde).
Es war technisch möglich, dass ein Thread von einer Wartezeit zurückkehrt, ohne von einem anderen Prozess ausgelöst zu werden (dies ist ein echtes falsches Aufwecken), aber in all meinen vielen Jahren, in denen ich an Pthreads gearbeitet habe, sowohl bei der Entwicklung / beim Service des Codes als auch als Benutzer von ihnen habe ich nie eine davon erhalten. Vielleicht lag das nur daran, dass HP eine anständige Implementierung hatte :-)
In jedem Fall behandelte derselbe Code, der den fehlerhaften Fall behandelt hat, auch echte falsche Aufweckvorgänge, da das Flag für verfügbare Arbeit für diese nicht gesetzt wäre.