Pthread: sicherstellen cond_signal erst nach Aufruf cond_wait



  • Hallo,
    Gibt es eine Möglichkeit zu überprüfen, ob ein pthread_cond_wait aufgerufen wurde, damit man ein pthread_cond_signal nicht zu früh abgibt?

    Ich bin auf dieses Problem bei der Initialisierung meines Programms gestoßen. Ich habe das jetzt anders gelößt und es ist somit kein Problem mehr, aber dennoch weiß ich keine Antwort darauf, falls es mir mal woanders begegnen würde.

    Wenn man ein cond_signal ohne das passende Gegenstück aufruft, bekommt man nur ne 0 zurück.
    Das Signal wird auch nicht gespeichert, sodass ein cond_wait nicht einfach weiter macht.

    sleep() ist keine Lösung! 😉

    Ich hoffe es ist klar, was ich meine.

    Gruß,

    Philipp



  • Beim Wait gibst Du ja einen Mutex zusätzlich zur Condition an. Dieser ist genau dafür gedacht, denn cond_wait entsperrt diesen Mutex während des Wartens, und sperrt ihn wieder, wenn es ein Signal empfängt. Damit kannst Du (vorausgesetzt der Mutex ist nicht sowieso entsperrt) durch Sperren des Mutex vor cond_signal sicherstellen, dass cond_wait gerade wartet.

    Ganz allgemeiner Ablauf (vorne die Thread-Nummer):

    (1) Neuen Thread starten (2)

    (2) Mutex sperren
    (2) bla bla bla

    (1) Mutex sperren -> ist bereits durch (2) gesperrt, mutex_lock(mutex) blockiert also

    (2) cond_wait(cond, mutex) -> entsperrt Mutex, damit darf (1) ihn sperren

    (1) mutex_lock(mutex) kehrt zurück, Mutex ist jetzt gesperrt
    (1) cond_signal(cond)

    (2) cond_wait kehrt zurück und sperrt den Mutex -> ist aber noch durch (1) gesperrt, blockiert also noch bis

    (1) mutex_unlock(mutex) damit (2) den lock erhält und weitermachen kann



  • Hi,
    ja genau so ists bei mir auch implementiert.

    Aber ist denn sichergestellt, dass (2) auch bereits soviel Rechenzeit hatte, dass es den Mutex schon erstmalig locken konnte?
    Könnte es nicht passieren, dass (1) nach dem create schneller beim lock ist als thread (2)?

    irgendwer ne Ahnung?



  • Hallo Philipp,

    ich verlasse mich nie auf eine 'gedachte' Reihenfolge bei der Ausführung von Threads. Das Betriebsystem würfelt die Ausführungsreihenfolge,
    insbesondere unter Last stark durcheinander.

    Bevor ich in eine Wait Condition gehe,
    prüfe ich anhand von Status Variabeln, ... ob es überhaupt Sinn macht zu warten.
    Auch warte ich nie endlos auf eine Condition, sondern arbeite immer mit timeout.

    Gegebenfalls wiederhole ich bei erfolglosem Warten, oft dann mit einer Logmeldung. Das hilft bei Deadlocks Hinweise zu bekommen.
    Ich wiederhole nie endlos, ...

    Ich hoffe das Hilft dir etwas.

    Gruß Frank



  • Hallo Frank,

    Vielen Dank für deine Antwort.

    In meinem Problem habe ich einen Daemon-Thread, der eine queue abarbeitet und leert. Die Funktion, die die queue wieder füllt ruft dann ein cond_signal auf um den daemon wieder zu wecken. Somit war ein timeout hier nur bedingt möglich.

    Ich hatte auch versucht mit flags zu arbeiten, nur wusste ich nicht, wo bzw wann ich diese setzen sollte um nicht wieder in das gleiche race-Problem zu rennen. Aber ich bin mir gerade nicht mehr ganz sicher, ob das nicht hätte doch klappen können, wie du es vorschlägst. Hab den Code nicht vor mir.

    Im übrigen habe ich mein Problem mit semaphoren gelöst. Sind sehr leicht zu verstehen (zumindest in der Komplexität wie ich sie benutze 😉 ) und haben noch die Vorteile, dass sie Signale speichern, selbst wenn man noch kein wait hat, sowie viel schneller sind als meine Mutex-Lösung.



  • Hallo Phillip,

    ich denke du machst es schon genau so richtig.

    Ich hatte auch versucht mit flags zu arbeiten

    Du hast den Queue Status (leer oder gefüllt), das sind genau die Stati,
    die ich meine, in diesem Fall sind keine weiteren Flags sinnvoll.

    Im übrigen habe ich mein Problem mit semaphoren gelöst.

    Genau so geht es, du musst den Zugriff auf die Queue über Semaphore schützen.
    Am besten über Getter und Setter und in den Methoden/Funktionen dann die Semaphore (am besten scoped lock/unlock) bedienen.

    Somit war ein timeout hier nur bedingt möglich.

    Nötig ist ein Timeout nicht, möglich aber immer. Du mußt auch oder gerade als deamon sauber terminieren. Normalerweise 'fällst' du bei einem beliebigen Signal
    aus dem Condition Wait heraus. Dann kann man ein Terminierungsflag prüfen,
    seinen queustatus prüfen und eventuell wieder warten ...

    Ich warte immer nur endlich (z.B. eine Sekunde) und prüfe zyklisch,
    meine 'Stati', dann darf auch 'mal' ein Signal verloren gehen.
    Das würde dann zwar Zeit 'kosten' aber nicht zu einem Hänger führen ...

    Wie auch immer hört sich gut an was du da machst ...

    Gruß Frank


Anmelden zum Antworten