Newsgroup: it.comp.lang.c++
Titolo: Valore ritorno std::condition_variable::wait_for

Ho un problema col valore di ritorno di std::condition_variable::wait_for.
 
Il mio test usa due thread che condividono lo stesso oggetto di sincronizzazione:
 
-T1 rimane in attesa su una condition_variabile::wait_for con un timeout X secondi.
-T2 attende N secondi e poi sveglia i thread in attesa (notify_all).
 
1- Se N < X (la notifica arriva prima del timeout) il valore di ritorno di wait_for è sempre no_timeout.
 
2- Se N > X (la notifica arriva dopo il timeout) il valore di ritorno di wait_for è a intermittenza timeout e no_timeout. 
 
Nel secondo caso il tempo di attesa è coerente, è solo il valore di ritorno che varia. Non riesco a capire il motivo. 
 

Il 24/01/19 11:00, _merlinO_ ha scritto:

difficile dire il motivo
un bug nella implementazione usata o nel tuo programma ?
poiche ne sono incuriosito hai un piccolo programma per testare questa 
cosa specificando l'os e la versione del compilatore  che hai usato ?
 


Semplice, hai X < N < 2X (quasi sicuramente)
supponiamo che i due thread partano in contemporanea,
1) il 1° thread arriva al timeout e quindi riparte.
2) Il 2° thread arriva a N, manda la notifica ed hai no_timeout.
3) I due thread ripartono da zero e si ritorna al caso (1)
 
Se provi con 2X < N < 3X avrai in sequenza due timeout ed un no_timeout
 

 Se provi con 2X < N < 3X avrai in sequenza due timeout ed un no_timeout
 
Non ho ripartenza, sono test spot, creo tutto ad ogni giro


Ma X e N sono fissi? Chi causa la chiusura dei thread?
Se è l'evento che ferma tutto è normale che sia così, si ricade sempre 
nella condizione iniziale.
Ad ogni avvio si va nel caso (1) se X < N altrimenti si salta 
direttamente al caso (2) ed infine il caso (3) diventa la chiusura.
 
... scusa, sopra avevo scritto 'riparte' ma intendevo che si rimette in 
wait.
 
 

 cosa specificando l'os e la versione del compilatore  che hai usato ?
 
Windows con VS2015
 
Ho messo un esempio qui: 
http://cpp.sh/4vpuu
 
 
anche in questo caso si verifica il problema


commenta la riga:
     while (!m_notified)  // avoid spurious wakeup
 
non esce dal ciclo finché non diventa true
 
 
 

 non esce dal ciclo finché non diventa true
 
Lo so ma prima di inviare la notify_one viene messa a true, comunque non è questo il problema, nella prima versione non c'era. 
 
Ho provato a reimplementare con un altro sistema di sincronizzazione ma non cambia, a questo punto credo che il problema sia il thread che produce la notifica. 

 
 
anziché usare il main thread non è più semplice usare due thread 
separati dal flusso principale?
 

Il 24/01/19 11:00, _merlinO_ ha scritto:

Ho esaminato il programma e mi sembra corretto.
Il Timeout succede perche avviene proprio un timeout
 
Qui:    const auto result = obj->Wait(1s);
gli dici al thread di attendere al max 1 secondo oppure che venga 
notificato
E' normale che alcuni threads con tempi cosi bassi vadano in timeout
Se porti il tempo di attesa ad esempio a 10s il timeout non si verifica
 
 
Compilato sotto linux con
const auto result = obj->Wait(1s);
 
  g++ -std=c++17 -Wall main.cpp -lpthread
 
1: 0ms Timeout
2: 2000ms Timeout
3: 4000ms Timeout
4: 6000ms Timeout
5: 8000ms No timeout
6: 10001ms Timeout
7: 12001ms Timeout
8: 14001ms Timeout
9: 16001ms Timeout
10: 18001ms Timeout
11: 20002ms Timeout
12: 22002ms Timeout
13: 24002ms Timeout
14: 26002ms Timeout
15: 28002ms Timeout
16: 30003ms Timeout
17: 32003ms No timeout
18: 34003ms Timeout
19: 36003ms Timeout
20: 38003ms Timeout
 
con
const auto result = obj->Wait(10s);
 
1: 0ms No timeout
2: 2000ms No timeout
3: 4000ms No timeout
4: 6000ms No timeout
5: 8000ms No timeout
6: 10001ms No timeout
7: 12001ms No timeout
8: 14001ms No timeout
9: 16001ms No timeout
10: 18002ms No timeout
11: 20002ms No timeout
12: 22002ms No timeout
13: 24003ms No timeout
14: 26003ms No timeout
15: 28003ms No timeout
16: 30003ms No timeout
17: 32004ms No timeout
18: 34004ms No timeout
19: 36004ms No timeout
20: 38004ms No timeout
 
I threads vengono tutti notificati
 
 
Quello che non capisco e' questa:
inline string Time()
{
   static auto start = high_resolution_clock::now();
   return 
std::to_string(duration_cast<milliseconds>(high_resolution_clock::now() 
- start).count()) + "ms ";
}
 
 
Che senso ha misurare l'esecuzione di due istruzione in sequenza (now - 
start) ?
dove poi Time() viene usata nella print ?
 
 
 
 
 

Il 27/01/19 09:18, enoquick ha scritto:

Rettifico sulla Time()
start e' static quindi viene calcolata solo la prima volta
 

 dove poi Time() viene usata nella print ?
 
E' voluto, volevo calcolare il ritardo che si accumula di volta in volta. Poiché i tempi sono semplici (1s timeout, 2s evento) è comunque facile fare il calcolo di cosa è accaduto. 
 
Il mio scopo è proprio quello di testare il timeout, quando non lo raggiungo e l'evento viene segnalato in tempo tutto funziona. 
Se invece l'evento non viene segnalato in tempo wait_for (al netto di errori miei) sembra sempre aspettare l'evento. 
 
*La cosa strana* è che i cicli sono ogni 2s anziché 1s (timeout), la wait_for dovrebbe uscire prima che la notifica arrivi. 
I tempi di test dovrebbero essere sufficienti, di solito i thread reagiscono nell'ordine dei ms. 
 
Ho implementato lo stesso template con QT e funziona come mi aspetto. Non riesco proprio a capire perché... 

Il giorno domenica 27 gennaio 2019 16:21:26 UTC+1, enoquick ha scritto:
 
Ho fatto una versione ultra-semplificata, sul sito funziona, su Windows il risultato è questo: 
 
1: waitTime=1001ms (Timeout) / loopTime=5003ms
2: waitTime=1000ms (Timeout) / loopTime=5000ms
3: waitTime=1000ms (Timeout) / loopTime=5000ms
4: waitTime=1000ms (Timeout) / loopTime=5000ms
5: waitTime=999ms (No timeout) / loopTime=5000ms
6: waitTime=999ms (No timeout) / loopTime=5000ms
7: waitTime=1000ms (Timeout) / loopTime=5001ms
8: waitTime=1000ms (Timeout) / loopTime=5001ms
9: waitTime=1000ms (Timeout) / loopTime=5000ms
10: waitTime=999ms (No timeout) / loopTime=5000ms
11: waitTime=999ms (No timeout) / loopTime=5000ms
12: waitTime=1000ms (Timeout) / loopTime=5000ms
13: waitTime=1000ms (Timeout) / loopTime=5000ms
14: waitTime=999ms (No timeout) / loopTime=5000ms
15: waitTime=1000ms (Timeout) / loopTime=5000ms
16: waitTime=1000ms (Timeout) / loopTime=5000ms
17: waitTime=999ms (No timeout) / loopTime=5000ms
18: waitTime=1000ms (Timeout) / loopTime=5000ms
19: waitTime=999ms (No timeout) / loopTime=5000ms
20: waitTime=1000ms (Timeout) / loopTime=5000ms
 
http://cpp.sh/8z2xk
 
 

 Ho implementato lo stesso template con QT e funziona come mi aspetto. Non riesco proprio a capire perché...
 
Alla fine è un baco dell'implementazione Microsoft 
https://developercommunity.visualstudio.com/content/problem/193041/the-visual-c-2017-condition-variable-implementatio.html
 
 

Il 30/01/19 03:24, _merlinO_ ha scritto:

Ma era segnalato nel febbraio 2018,quasi un anno fa
Possibile che non lo abbiano ancora corretto ?
Hai provato con vs2017 aggiornato all'ultima patch ?
 
 

 Hai provato con vs2017 aggiornato all'ultima patch ?
 
Sì, non l'hanno ancora corretto, o non è semplice o non è importante (per loro).

Il 31/01/19 04:37, _merlinO_ ha scritto:

Avranno altre priorita da sistemare
Vs2017 ha ancora bachi a correggere segnalati nell'apposito forum.
E non solo c++ ovviamente