5

Spurious wakup è consentito da varie piattaforme. Per contrastare questo, scriviamo di seguito meccanismo di looping:In che modo condition_variable :: wait_for() si occupa di wakeups spuri?

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

Stessa cosa è comprensibile per conditional_variable::wait_until().
Ma guardate qui sotto esempio:

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

Immaginate che, sveglia spuria è accaduto a 1 secondo. Il timeout non è ancora stato raggiunto.
Attenderà altri 10 secondi? Ciò porterebbe a un ciclo infinito, che sono sicuro non dovrebbe accadere. Dal codice sorgente, internamente wait_for() chiama wait_until().

Voglio capire, in che modo lo wait_for() si occupa di wakeups spuri?

+2

Non è così. Devi controllarlo tu stesso o usare il sovraccarico che fa per te (quello che prende un predicato). –

+0

@MaiLongdong, il predicato viene utilizzato solo per contrastare tali wakeup. Anche 'wait_for()' se funziona bene nella mia piattaforma, non garantisce che funzionerà ovunque, perché i risvegli spuri dipendono dalla piattaforma. – iammilind

+1

Se non vuoi 'wait_for' 10 secondi usa' wait_until'' now() '+ 10 secondi :-) –

risposta

4

voglio capire, come fa wait_for() offerte con wakeup spurie?

Non funziona.

Questa funzione viene in genere utilizzata in una situazione in cui se si sveglia in modo spurio, si desidera eseguire comunque un altro lavoro. E se non ti svegli spuriamente, vuoi forzare un risveglio "spurio" prima che sia passato il tempo duration. Ciò significa che in genere non viene utilizzato in un ciclo come mostrato, esattamente per le ragioni che hai indicato. Cioè timeout e wake up spuri sono trattati identicamente.

Ora potreste chiedervi, bene, cosa fa la versione del predicato, in quanto implica un ciclo?

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

Questo viene specificato di avere gli stessi effetti:

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

Il wait_until variazione fa distinguere tra alti wake spurie e timeout. Lo fa con un ciclo come questo:

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

Ecco ciò che la norma ha da dire su wakeups spurie:

30,5 variabili Stato [thread.condition]

variabili Stato forniscono primitive di sincronizzazione utilizzate per bloccare un filo fino a quando comunicato da qualche altro thread che alcune condizioni sono soddisfatte o fino al raggiungimento di un'ora di sistema.

...

10 Nota: È responsabilità dell'utente assicurarsi che il thread in attesa non erroneamente per scontato che il thread è terminato se esperienza wakeups spurie.

Dalla formulazione sembra abbastanza chiaro che l'utente abbia la responsabilità di occuparsi di wakeup spurie.

1

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

            
 

questo è sicuramente una cosa sbagliata da fare e quindi non ha senso discutere come risolvere il problema per il caso di wakeups spuri, come si è rotto, anche per il caso di wakeups ordinari, in quanto il la condizione di attesa non viene riesaminata dopo il ritorno dall'attesa.

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

Anche dopo la modifica, la risposta rimane la stessa: non si può davvero gestire "wakeups spurie", perché non si può davvero dire la ragione per la sveglia - può ben essere completamente wake wake a causa di una chiamata a condition_variable::notifyXXX prima che il timeout sia scaduto.

In primo luogo, si noti che non è possibile distinguere realmente tra una sveglia causata da una chiamata a condition_variable::notifyXXX e un risveglio causato, ad esempio, da un segnale POSIX [1]. Secondo, anche se i segnali POSIX non sono preoccupanti, il thread in attesa deve ancora riesaminare la condizione in quanto è possibile che la condizione cambi tra il momento in cui la variabile di condizione viene segnalata e il thread in attesa ritorna dalla condizione wait.

Quello che devi fare è trattare in modo speciale non svegliarsi prima del timeout, ma svegliarsi allo a causa del timeout.E questo dipende interamente dalle ragioni per avere un timeout in primo luogo, vale a dire sulle specifiche del dominio applicazione/problema.

[1] se aspettare su una variabile condizione è interrotto da un segnale, dopo l'esecuzione del gestore di segnale il filo è consentito sia di riprendere aspettare o tornare

+0

Il tuo primo para è giusto, in realtà l'ho scritto nel modo in cui ho postato. Dopo di ciò, l'ho cambiato in quello che c'è [cplusplus.com] (http://www.cplusplus.com/reference/condition_variable/condition_variable/wait_for/). È possibile modificare la risposta in base allo stato attuale della domanda. – iammilind