5

Spurious wakup jest dozwolone przez różne platformy. Aby przeciwdziałać tym, piszemy poniżej mechanizmu zapętlenie:W jaki sposób condition_variable :: wait_for() radzi sobie z fałszywymi wybudzeniami?

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

samo jest zrozumiałe dla conditional_variable::wait_until().
Ale spójrz na poniższy przykład:

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

Wyobraźmy sobie, że nieprawdziwy budzenia się na 1 sekundę. Przekroczono limit czasu.
Czy będzie czekać jeszcze 10 sekund? Doprowadziłoby to do nieskończonej pętli, której jestem pewien, że nie powinno się zdarzyć. Z kodu źródłowego wewnętrznie wait_for() dzwoni wait_until().

Chcę zrozumieć, w jaki sposób wait_for() radzi sobie z fałszywymi wybudzeniami?

+2

Nie. Musisz albo sprawdzić to samemu, albo użyć przeciążenia, które robi to za ciebie (ten, który bierze predykat). –

+0

@MaiLongdong, predykat jest używany do przeciwdziałania tylko takim przebudzeniom. Nawet 'wait_for()' jeśli działa dobrze na mojej platformie, nie gwarantuje, że będzie działać wszędzie, ponieważ zbędne wakesupy są zależne od platformy. – iammilind

+1

Jeśli nie chcesz 'wait_for' 10 sekund użyj' wait_until' 'now()' + 10 sekund :-) –

Odpowiedz

4

chcę zrozumieć, w jaki sposób wait_for() oferty z fałszywe przebudzenia?

Nie dotyczy.

Ta funkcja jest zwykle używana w sytuacji, gdy budzisz się fałszywie, mimo to chcesz wykonać inną pracę. A jeśli nie budzisz się fałszywie, chcesz wymusić "fałszywe" przebudzenie, zanim minie czas. Oznacza to, że nie jest zwykle używany w pętli, jak pokazano, z dokładnie z powodów, które podajesz. To znaczy. limity czasu i fałszywe pobudki są traktowane tak samo, jak .

Teraz możesz się zastanawiać, cóż, co robi wersja orzecznika, ponieważ implikuje pętlę?

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

ta jest określona, ​​aby mieć takie same skutki jak:

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

wait_until zmienności robi odróżnienie fałszywych ups budzenia oraz limity czasu. Robi to z pętlą podobną do tej:

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

Oto co średnia ma do powiedzenia o fałszywych wybudzeń:

30.5 zmienne Stan [thread.condition]

zmienne Stan zapewnić prymitywów synchronizacji wykorzystywane do blokowania wątku aż zgłoszone przez innego wątek, w którym spełniony jest pewien warunek lub do czasu osiągnięcia czasu systemowego.

...

10 Uwaga: Jest to odpowiedzialność użytkownika, aby upewnić się, że wątki czekają nie błędnie zakładają, że wątek zakończył jeśli doświadczenia fałszywych wybudzeń.

Ze sformułowania wyraźnie wynika, że ​​odpowiedzialność za postępowanie z fałszywymi wybudzeniami spoczywa na użytkowniku.

1

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

            
 

Jest to zdecydowanie źle rzeczą do zrobienia, a zatem nie ma sensu dyskutować, jak rozwiązać to dla przypadku fałszywych wybudzeń, jak to jest uszkodzony nawet w przypadku zwykłych wybudzeń, ponieważ warunek oczekiwania nie jest ponownie badany po powrocie z oczekiwania.

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

Nawet po edycji, odpowiedź pozostaje takie samo: naprawdę nie można obsłużyć „fałszywych wybudzeń”, bo tak naprawdę nie można powiedzieć o przyczynie wznawianiu - równie dobrze może być całkowicie legalne przebudzenie z powodu połączenia z numerem condition_variable::notifyXXX przed upływem limitu czasu.

Po pierwsze, należy pamiętać, że nie można naprawdę odróżnić pobudki spowodowanej przez połączenie z condition_variable::notifyXXX i wznowienia spowodowanego, na przykład, sygnałem POSIX [1]. Po drugie, nawet jeśli sygnały POSIX nie budzą niepokoju, wątek oczekujący wciąż musi ponownie przeanalizować warunek, ponieważ możliwe jest, aby warunek zmienił się od momentu zasygnalizowania zmiennej warunku, a wątek oczekiwania powróci z warunku oczekiwania.

To, co naprawdę musisz zrobić, to potraktować w specjalny sposób, nie budząc się przed upływem limitu czasu, ale budząc się z powodu przekroczenia limitu czasu.A to całkowicie zależy od powodów, dla których w ogóle ma miejsce przekroczenie limitu czasu, tj. Na specyfikę domeny aplikacji/problemu.

[1] czy czekać na zmiennej warunkowej jest przerwana przez sygnał, po wykonaniu obsługi sygnału wątek jest dozwolone bądź wznowić czekać lub wrócić

+0

Twoja pierwsza para ma rację, właściwie napisałem ją w ten sposób, kiedy ją opublikowałem. Potem zmieniłem go na to, co tam jest [cplusplus.com] (http://www.cplusplus.com/reference/condition_variable/condition_variable/wait_for/). Możesz edytować odpowiedź zgodnie z aktualnym stanem pytania. – iammilind

Powiązane problemy