What if the system time changes while I'm doing timed_wait with a duration?

别等时光非礼了梦想. 提交于 2021-01-27 03:54:19

问题


When using timed_wait on a boost::condition_variable with a duration, will the wait condition time out after the duration even if the user (or ntp) changes the system time?

E.g.,

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?
}

回答1:


As of the date of writing (Nov 2013), if the wall-clock time changes while you're waiting on a boost condition variable, you simply will get bad results.

If you don't have to use boost, you can use what is called the "monotonic clock." Since the monotonic clock is unaffected by wall-clock time changes, it is not vulnerable to the problem you described. You can safely wait 5 seconds using the pthreads API using something like this:

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);

You can check the implementation of boost::condition_variable. Maybe they will fix this some day. The implementation is here: http://svn.boost.org/svn/boost/trunk/boost/thread/pthread/condition_variable.hpp




回答2:


I believe it is a race condition, although a very rare one. The implementation of condition_variable::timed_wait() with a duration simply converts the value to a system_time using get_system_time()+wait_duration. If the system time changes between the time get_system_time() is called, and the calculated wait end time is reconverted to a tick-based counter for the underlying OS call, your wait time will be wrong.

To test this idea, on Windows, I wrote a simple program with one thread generating some output every 100ms, like this:

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

Another thread was setting the system time back one minute in the past every 100ms (this thread uses the OS-level "Sleep()" call which avoids conversions to system time):

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 );
}

The first thread, though supposed to output "Ping!" every 100 milliseconds, locked up rather quickly.

Unless I'm missing something, it seems Boost doesn't provide any APIs that avoid this problem of internal conversions to system time, leaving apps vulnerable to outside changes to the clock.




回答3:


I did see some problems with this, if your process also uses signals. I also use the Boost condition variables with a duration time.

We have a process that uses a POSIX timer to get accurate timing at 20 Hz. When this timer is activated and the time is set to an earlier date/time the condition variable blocks. When I change the time back to the original value the condition variable continues.

I copied the implementation from Boost and set the clock mode to CLOCK_MONOTONIC. Now the condition variable works correctly even if the time is changed.

It would have been helpful if there would have been a possibility to set the mode of a condition variable to monotonic, but that is not possible at this moment.




回答4:


issue was fixed at 1.61 develop branch:

https://svn.boost.org/trac/boost/ticket/6377



来源:https://stackoverflow.com/questions/4381095/what-if-the-system-time-changes-while-im-doing-timed-wait-with-a-duration

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!