2010-12-07 28 views
9

如果在持续时间为boost::condition_variable上使用timed_wait,则即使用户(或ntp)更改系统时间,等待条件是否会超时?如果在进行timed_wait和持续时间时系统时间发生了变化,该怎么办?

例如,

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,但对于记录你的答案的时候符合我的实验结果。 – indiv 2014-01-06 18:56:39

回答

9

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

如果你不要必须使用boost,你可以使用所谓的“单调时钟”。由于单调时钟不受挂钟时间变化的影响,因此它不易受到您所描述的问题的影响。您可以使用使用这样的并行线程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

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

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

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

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

2

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

为了验证这一想法,在Windows上,我写了一个简单的程序有一个线程产生一些输出每100ms,就像这样:

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

另一个线程设置系统时间回到一分钟过去每100毫秒(此线程使用的操作系统级别的“睡眠()”调用,它避免了转换系统时间):“中国平安”

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

第一个线程,但应该输出每100毫秒,锁定相当快。

除非我遗漏了一些东西,看来Boost并没有提供任何API来避免内部转换为系统时间的这个问题,从而使应用程序易受外部时钟变化的影响。

相关问题