8

在持续时间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

4 回答 4

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

于 2013-11-27T23:42:02.047 回答
2

我相信这是一种比赛条件,尽管非常罕见。具有持续时间的 condition_variable::timed_wait() 的实现只是使用 get_system_time()+wait_duration 将值转换为 system_time。如果系统时间在调用 get_system_time() 之间发生变化,并且计算出的等待结束时间被重新转换为底层操作系统调用的基于滴答的计数器,那么您的等待时间将是错误的。

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

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

另一个线程每 100 毫秒将系统时间设置回过去一分钟(该线程使用操作系统级别的“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 来避免内部转换为系统时间的问题,从而使应用程序容易受到外部时钟更改的影响。

于 2013-10-24T19:10:34.720 回答
1

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.

于 2012-01-09T14:26:01.743 回答
1

问题已在 1.61 开发分支修复:

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

于 2016-08-01T09:34:16.663 回答