Eine falsche Erklärung für das Aufwecken klingt wie ein Fehler, der es einfach nicht wert ist, behoben zu werden.

30

Laut Wikipedia-Artikel über Spurious Wakeups

msgstr "Ein Thread wird möglicherweise aus seinem Wartezustand geweckt, obwohl kein Thread die Bedingungsvariable signalisiert hat".

Obwohl ich über dieses "Feature" Bescheid wusste, wusste ich erst im selben Artikel, was es tatsächlich verursachte

"Falsches Aufwecken mag seltsam klingen, aber auf einigen Multiprozessorsystemen kann das vollständige Vorhersagen des Aufweckens von Zuständen alle Operationen von Zustandsvariablen erheblich verlangsamen."

Klingt nach einem Fehler, der es einfach nicht wert ist, behoben zu werden, oder?

James
quelle
1
verwandt: "Warum hat pthread_cond_wait falsches Aufwecken?", stackoverflow.com/questions/8594591/…
Florian Castellane

Antworten:

39

TL; DR Die Annahme ("Vertrag") von fehlerhaften Aufweckvorgängen ist eine sinnvolle architektonische Entscheidung, die getroffen wurde, um realistisch robuste Implementierungen von Thread-Sheduler zu ermöglichen.

"Leistungsüberlegungen" sind hier irrelevant, es handelt sich lediglich um Missverständnisse, die weit verbreitet wurden, weil sie in einem veröffentlichten maßgeblichen Verweis angegeben wurden. (Autoritative Verweise können Fehler enthalten, fragen Sie einfach Galileo Galilei. ) Der Wikipedia-Artikel behält den Verweis auf den von Ihnen zitierten Verweis bei, nur weil er perfekt zu den formalen Richtlinien zum Zitieren des veröffentlichten Verweises passt.

Viel zwingenderer Grund für die Einführung des Konzepts des falschen Aufwachens ist in dieser Antwort auf SO angegeben , die auf zusätzlichen Details basiert, die in einer (älteren Version) dieses Artikels bereitgestellt wurden:

Der Wikipedia- Artikel über falsches Aufwecken hat diesen Leckerbissen:

Die pthread_cond_wait()Funktion unter Linux wird über den futexSystemaufruf implementiert . Jeder blockierende Systemaufruf unter Linux kehrt abrupt mit zurück, EINTRwenn der Prozess ein Signal empfängt. ... pthread_cond_wait()kann das Warten nicht neu starten, da es in der kurzen Zeit außerhalb des futexSystemaufrufs ein echtes Aufwecken verpassen kann ...

Denken Sie nur daran ... wie bei jedem Code kann es beim Thread-Scheduler zu einem vorübergehenden Blackout kommen, weil in der zugrunde liegenden Hardware / Software etwas Ungewöhnliches passiert. Natürlich sollte darauf geachtet werden, dass dies so selten wie möglich vorkommt, aber da es keine 100% robuste Software gibt, ist es vernünftig anzunehmen, dass dies passieren kann , und auf die ordnungsgemäße Wiederherstellung zu achten, falls der Scheduler dies erkennt (z. B. durch Beobachtung fehlender Herzschläge ).

Wie kann sich der Scheduler nun erholen, wenn man bedenkt, dass beim Blackout einige Signale fehlen können, die wartende Threads benachrichtigen sollen? Wenn der Scheduler nichts unternimmt, bleiben die genannten "unglücklichen" Threads hängen und warten für immer - um dies zu vermeiden, sendet der Scheduler einfach ein Signal an alle wartenden Threads.

Dies macht es notwendig, einen "Vertrag" abzuschließen, über den wartende Threads ohne Angabe von Gründen benachrichtigt werden können. Um genau zu sein, gibt es einen Grund - Scheduler-Blackout - aber da der Thread (aus gutem Grund) so konzipiert ist, dass er die internen Implementierungsdetails des Schedulers nicht berücksichtigt, ist es wahrscheinlich besser, diesen Grund als "falsch" zu kennzeichnen.


Aus Fadenperspektive ähnelt dies einem Postelschen Gesetz (auch bekannt als Robustheitsprinzip ).

Sei konservativ in dem, was du tust, sei liberal in dem, was du von anderen akzeptierst

Die Annahme von fälschlichen Aufweckvorgängen zwingt den Thread dazu, konservativ zu sein, was er tut : Bedingung bei Benachrichtigung anderer Threads festlegen und liberal, was er akzeptiert : Die Bedingung bei Rückkehr von wait prüfen und wait wiederholen, wenn sie noch nicht da ist.

Mücke
quelle
10
Ugh ... Postels Gesetz ... der Grund, warum HTML und alle Arten von Web-Technologien so viel Mist enthalten (z. B. HTML-Akzeptanz von schlechtem Tag-Nesting). Davon abgesehen eine gute Antwort.
Thomas Eding
3
Postels Gesetz besagt, dass viele Bugs jahrelang unbemerkt bleiben, denn selbst wenn Ihre Funktion die falsche Ausgabe zurückgibt, scheint die App immer noch zu funktionieren! Beste Erfindung aller Zeiten.
Pacerier
2
@Pacerier: Die Funktion, die eine falsche Ausgabe zurückgibt, entspricht nicht dem Postelschen Gesetz (konservativer Teil).
YvesgereY
@Pacerier: OTOH, die Forderung, dass andere Komponenten streng sind, damit Fehler früher erkannt werden können, ist eine interessante Position, die sich auf das Fail-Fast-Prinzip und das vertragsbasierte Design bezieht.
YvesgereY
1

Es lohnt sich nicht, dies zu korrigieren, da der Anrufercode ohnehin dieselbe Behandlung (Überprüfung der Bedingung) verwenden sollte, um mit der Racebedingung fertig zu werden.

Eine Behandlung für zwei Probleme, die ich wie folgt zusammenfasse:

Versehentliches Aufwecken: Das Warten auf einen Thread ist geplant, bevor der Zustand hergestellt wurde.
Erzwungenes Überschlafen: Der wartende Thread wird eingeplant, nachdem der Zustand erneut verfälscht wurde.

Da das letztere passieren könnte, haben einige so weit gegangen, dass sie im Vertrag ein falsches Aufwecken eingeführt haben:

  • bewährte Praktiken durchzusetzen, indem Prädikatschleifen benötigt werden.
  • um etwas Freiheit für die Scheduler-Implementierung zu geben (einschließlich einer Notfallwiederherstellungsoption, wie von @gnat gezeigt).

SO Hinweis

YvesgereY
quelle
Ich würde dies gerne auf +1 setzen, aber für die Idee, dass jemand absichtlich falsche Weckrufe eingeführt hat, um Anrufer zu veranlassen, Prädikatschleifen hinzuzufügen, um erzwungene Schlafstörungen zu beheben. Ich finde das unvorstellbar.
Ruakh
"Die Absicht war, korrekten / robusten Code zu erzwingen, indem Prädikatschleifen benötigt wurden." Siehe den angegebenen Link.
YvesgereY