如果在我持续执行timed_wait时系统时间发生了变化怎么办?

时间:2010-12-07 20:10:47

标签: c++ boost timeout condition-variable time-wait

在具有持续时间的timed_wait上使用boost::condition_variable时,即使用户(或ntp)更改系统时间,等待条件是否会在持续时间后超时?

如,

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

4 个答案:

答案 0 :(得分:8)

截至撰写之日(2013年11月),如果您在等待提升条件变量时挂钟时间发生变化,您只会得到不好的结果。

如果你必须使用boost,你可以使用所谓的“单调时钟”。由于单调时钟不受壁钟时间变化的影响,因此不易受到您所描述的问题的影响。您可以使用pthreads API安全地等待5秒,使用以下内容:

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

您可以检查boost :: condition_variable的实现。也许他们有一天会解决这个问题。实施在这里:http://svn.boost.org/svn/boost/trunk/boost/thread/pthread/condition_variable.hpp

答案 1 :(得分:2)

我认为这是一种竞争条件,虽然非常罕见。带有持续时间的condition_variable :: timed_wait()的实现只是使用get_system_time()+ wait_duration将值转换为system_time。如果系统时间在调用get_system_time()的时间之间发生变化,并且计算出的等待结束时间重新转换为基础滴答计数器以进行基础OS调用,那么您的等待时间将是错误的。

为了测试这个想法,在Windows上,我编写了一个简单的程序,其中一个线程每100毫秒生成一些输出,如下所示:

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

另一个线程是每隔100ms将系统时间设置为过去一分钟(此线程使用操作系统级别的“Sleep()”调用,这样可以避免转换为系统时间):

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

第一个线程虽然应该输出“Ping!”每100毫秒,相当快地锁定。

除非我遗漏了某些东西,否则Boost似乎没有提供任何API来避免内部转换到系统时间的问题,从而使应用程序容易受到外部时钟变化的影响。

答案 2 :(得分:1)

如果你的过程也使用信号,我确实看到了一些问题。我还使用具有持续时间的Boost条件变量。

我们有一个使用POSIX定时器获得20 Hz精确定时的过程。当激活此计时器并将时间设置为较早的日期/时间时,条件变量将被阻止。当我将时间更改回原始值时,条件变量将继续。

我从Boost复制了实现,并将时钟模式设置为CLOCK_MONOTONIC。现在条件变量即使时间改变也能正常工作。

如果有可能将条件变量的模式设置为单调,那将会有所帮助,但目前这是不可能的。

答案 3 :(得分:1)

问题在1.61开发分支修复:

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