2010-12-07 10 views
9

Bei Verwendung von timed_wait auf einer boost::condition_variable mit einer Dauer, wird die Wartezeit Bedingung nach der Dauer Time auch wenn der Benutzer (oder ntp) ändert die Systemzeit?Was passiert, wenn sich die Systemzeit ändert, während ich timed_wait mit einer Dauer mache?

Z. B.

boost::posix_time::time_duration wait_duration(0, 0, 1, 0); // 1 sec 
// ** System time jumps back 15 minutes here. ** 
if(!signal.timed_wait(lock, wait_duration)) 
{ 
    // Does this condition happen 1 second later, or about 15 minutes later? 
} 
+0

@Roddy: OK, aber der Ordnung halber Ihre Antwort meine experimentellen Ergebnisse zu der Zeit angepasst. – indiv

Antwort

9

Zum Zeitpunkt des Schreibens (Nov 2013), wenn die Wanduhr-Zeit sich ändert, während Sie auf eine Boost-Bedingung-Variable warten, werden Sie einfach schlechte Ergebnisse bekommen.

Wenn Sie nicht Boost verwenden müssen, können Sie verwenden, was die "monotone Uhr" genannt wird. Da die monotone Uhr nicht von Änderungen der Wanduhrzeit beeinflusst wird, ist sie nicht anfällig für das von Ihnen beschriebene Problem. Sie können sicher 5 Sekunden warten, bis die pThreads API mit so etwas wie dies mit:

pthread_condattr_t attr; 
pthread_cond_t cond; 
struct timespec ts; 

pthread_condattr_init(&attr); 
pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); 
pthread_cond_init(&cond, &attr); 
pthread_condattr_destroy(&attr); 
clock_gettime(CLOCK_MONOTONIC, &ts); 
ts.tv_sec += 5; 
pthreead_cond_timedwait(&cond, &mutex, &ts); 

Sie können prüfen, die Umsetzung der boost :: condition_variable. Vielleicht werden sie das eines Tages beheben. Die Implementierung ist hier: http://svn.boost.org/svn/boost/trunk/boost/thread/pthread/condition_variable.hpp

1

habe ich ein paar Probleme mit diesem sehen, wenn Ihr Prozess auch Signale verwendet. Ich verwende auch die Boost-Bedingungsvariablen mit einer Zeitdauer.

Wir haben einen Prozess, der einen POSIX-Timer verwendet, um eine genaue Zeitmessung bei 20 Hz zu erhalten. Wenn dieser Timer aktiviert ist und die Uhrzeit auf ein früheres Datum/eine frühere Uhrzeit eingestellt ist, blockiert die Zustandsvariable. Wenn ich die Zeit auf den ursprünglichen Wert zurückstelle, wird die Zustandsvariable fortgesetzt.

Ich kopierte die Implementierung von Boost und stellen Sie den Uhrmodus auf CLOCK_MONOTONIC. Jetzt funktioniert die Zustandsvariable korrekt, auch wenn die Zeit geändert wird.

Es wäre hilfreich gewesen, wenn es eine Möglichkeit gegeben hätte, den Modus einer Zustandsvariablen monoton zu setzen, aber das ist in diesem Moment nicht möglich.

2

Ich glaube, es ist eine Race Condition, obwohl eine sehr seltene. Die Implementierung von condition_variable :: timed_wait() mit einer Dauer konvertiert einfach den Wert in eine system_time mit get_system_time() + wait_duration. Wenn sich die Systemzeit zwischen dem Zeitpunkt ändert, an dem get_system_time() aufgerufen wird, und der berechneten Wartezeitendezeit in einen tickbasierten Zähler für den zugrunde liegenden Betriebssystemaufruf konvertiert wird, ist die Wartezeit falsch.

diese Idee zu testen, auf Windows, schrieb ich ein einfaches Programm mit einem Thread all 100ms eine Ausgabe zu erzeugen, wie folgt aus:

for (;;) 
{ 
    boost::this_thread::sleep(boost::get_system_time() + 
     boost::posix_time::milliseconds(100)); 
    std::cout << "Ping!" << std::endl; 
} 

Ein anderer Thread die Systemzeit wieder eine Minute lang in der Vergangenheit einstellt jeder 100ms (dieser Thread verwendet die OS-Ebene "Sleep()" Aufruf, die Conversions Systemzeit vermeidet): "Ping"

for (;;) 
{ 
    Sleep(100); 
    SYSTEMTIME sysTime; 
    GetSystemTime(&sysTime); 
    FILETIME fileTime; 
    SystemTimeToFileTime(&sysTime, /*out*/&fileTime); 
    ULARGE_INTEGER fileTime64 = (ULARGE_INTEGER(fileTime.dwHighDateTime) << 32) | 
     fileTime.dwLowDateTime; 
    fileTime64 -= 10000000 * 60; // one minute in the past 
    fileTime.dwHighDateTime = (fileTime64>>32) & 0xFFFFFFFF; 
    fileTime.dwLowDateTime = fileTime64 & 0xFFFFFFFF; 
    FileTimeToSystemTime(&fileTime, /*out*/&sysTime); 
    SetSystemTime(&sysTime); 
} 

Der erste Thread, obwohl die Ausgabe soll alle 100 Millisekunden, ziemlich schnell abgeschlossen.

Sofern ich etwas vermisse, scheint Boost keine APIs zur Verfügung zu stellen, die dieses Problem interner Konvertierungen zur Systemzeit vermeiden und Apps für äußere Änderungen der Uhr anfällig machen.