5

Spurious wakup ist von verschiedenen Plattformen erlaubt. Um dem entgegenzuwirken, dass, schreiben wir unter Looping-Mechanismus:Wie funktioniert condition_variable :: wait_for() mit unechten Wakeups?

while(ContinueWaiting()) 
    cv.wait(lock); // cv is a `std::conditional_variable` object 

Das Gleiche gilt für conditional_variable::wait_until() verständlich ist.
Aber Beispiel unten aussehen:

const auto duration = Returns_10_seconds(); 
while(!Predicate()) 
    cv.wait_for(lock, duration); 

dass Stellen Sie sich vor, passiert falsche Wakeup bei 1 Sekunde. Timeout ist noch nicht erreicht.
Wird es noch weitere 10 Sekunden warten? Dies würde zu einer Endlosschleife führen, von der ich sicher bin, dass sie nicht passieren sollte. Vom Quellcode intern wait_for() ruft wait_until().

Ich möchte verstehen, wie sich wait_for() mit unechten Wakeups befasst?

+2

Es tut es nicht. Sie müssen es entweder selbst überprüfen oder die Überladung verwenden, die das für Sie tut (diejenige, die ein Prädikat übernimmt). –

+0

@MaiLongdong, wird das Prädikat verwendet, um nur solche Wakeups zu kontern. Sogar 'wait_for()' wenn es in meiner Plattform gut funktioniert, garantiert nicht, dass es überall funktioniert, weil unechte wakesups plattformabhängig sind. – iammilind

+1

Wenn du nicht 'wait_for' 10 Sekunden lang willst benutze' wait_until' 'now()' + 10 Sekunden :-) –

Antwort

4

ich verstehen will, wie funktioniert wait_for() beschäftigt sich mit falsche Wakeups?

Es tut es nicht.

Diese Funktion wird normalerweise in einer Situation verwendet, in der Sie, wenn Sie fälschlicherweise aufwachen, trotzdem eine andere Arbeit machen möchten. Und wenn Sie nicht falsch aufwachen, wollen Sie ein "falsches" Aufwachen erzwingen, wenn duration vergangen ist. Dies bedeutet, dass es in der Regel nicht in einer Schleife verwendet wird, wie Sie es zeigen, aus genau den Gründen, die Sie angeben. I.e. Timeouts und unechte Weckvorgänge werden identisch behandelt.

Jetzt fragen Sie sich vielleicht, was macht die Prädikat-Version, da es eine Schleife impliziert?

return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred)); 

Die wait_until Variation tut unterscheiden zwischen unechten Wake ups und Timeouts

:

template <class Rep, class Period, class Predicate> 
bool 
wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time, 
     Predicate pred); 

Diese Angabe ist als die gleiche Wirkung haben. Es tut so mit einer Schleife wie folgt:

while (!pred()) 
    if (wait_until(lock, abs_time) == cv_status::timeout) 
     return pred(); 
return true; 
2

Hier ist, was der Standard über unechte Wakeups zu sagen hat:

30,5 Bedingungsvariablen [thread.condition]

Bedingungsvariablen liefern Synchronisations Primitiven verwendet, um einen Thread zu blockieren, bis sie von einer anderen mitgeteilt Thread, dass eine Bedingung erfüllt ist oder bis eine Systemzeit erreicht ist.

...

10 Hinweis: Es liegt in der Verantwortung des Anwenders, um sicherzustellen, dass wartenden Threads nicht davon ausgehen, fälschlicherweise, dass der Faden, wenn sie Erfahrung unechte Wakeups beendet hat.

Aus der Formulierung scheint es ziemlich klar, dass die Verantwortung für den Umgang mit unechten Wakeups auf den Benutzer ist.

1

            
 
  
              
    const auto duration = Returns_10_seconds(); 
    while(cv.wait_for(lock, duration) == std::cv_status::timeout); 

            
 

Dies ist definitiv eine falsche Sache zu tun und somit keinen Sinn macht, zu diskutieren, wie es für den Fall der unechten Wakeups zu beheben, wie es auch für den Fall der gewöhnlichen Wakeups gebrochen ist, weil die Die Wartebedingung wird nach der Rückkehr von der Warte nicht erneut überprüft.

const auto duration = Returns_10_seconds(); 
while(!Predicate()) 
    cv.wait_for(lock, duration); 

Auch nach dem bearbeiten, bleibt die Antwort die gleiche: man kann nicht wirklich „unechte Wakeups“ behandeln, weil man nicht wirklich den Grund für die Wake-up sagen kann - es auch ein vollständig sein kann, Legit Wakeup aufgrund eines Anrufs zu condition_variable::notifyXXX vor dem Timeout abgelaufen ist.

Beachten Sie zuerst, dass Sie nicht wirklich unterscheiden zwischen einem Aufwecken, der durch einen Anruf auf condition_variable::notifyXXX verursacht wurde, und einem Weckruf, der zum Beispiel durch ein POSIX-Signal verursacht wurde [1]. Zweitens, auch wenn POSIX-Signale keine Rolle spielen, muss der wartende Thread die Bedingung noch einmal überprüfen, da die Bedingung zwischen dem Zeitpunkt, zu dem die Zustandsvariable signalisiert wird, und dem wartenden Thread von der Zustandswarte zurückkehrt.

Was Sie wirklich tun müssen, ist in einer besonderen Weise zu behandeln, nicht vor dem Timeout aufwachen, aber wegen Timeout aufwachen.Und das hängt vollständig von den Gründen ab, um eine Auszeit an erster Stelle zu haben, d. H. An den Besonderheiten der Anwendung/Problemdomäne.

[1], wenn auf einer Bedingungsvariable warten durch ein Signal unterbrochen wird, nachdem der Thread die Signal-Handler Ausführung erlaubt wird entweder warten wieder aufnehmen oder Rückkehr

+0

Dein 1. Para ist richtig, eigentlich habe ich es in der aktuellen Art geschrieben als ich gepostet habe. Danach habe ich es geändert, was es gibt [cplusplus.com] (http://www.cplusplus.com/reference/condition_variable/condition_variable/wait_for/). Sie können die Antwort entsprechend dem aktuellen Status der Frage bearbeiten. – iammilind

Verwandte Themen