C++ 在等待std::condition_变量时,如何处理系统时钟的变化?

C++ 在等待std::condition_变量时,如何处理系统时钟的变化?,c++,c++11,time,condition-variable,system-clock,C++,C++11,Time,Condition Variable,System Clock,我试图在C++11中实现一些跨平台代码。这段代码的一部分使用。当我需要对信号量进行定时等待时,我使用或等待 我遇到的问题是,基于POSIX的系统上条件_变量的标准实现似乎依赖于(另请参见:) 这意味着,如果系统时钟更改为过去的某个时间,我的条件变量的阻塞时间将远远超过我的预期。例如,如果我希望我的条件变量在1秒后超时,如果有人在等待期间将时钟向后调整10分钟,则条件变量将阻塞10分钟+1秒。我已经确认这是Ubuntu 14.04 LTS系统上的行为 我需要依靠这个超时来至少在某种程度上准确(即,

我试图在C++11中实现一些跨平台代码。这段代码的一部分使用。当我需要对信号量进行定时等待时,我使用或等待

我遇到的问题是,基于POSIX的系统上条件_变量的标准实现似乎依赖于(另请参见:)

这意味着,如果系统时钟更改为过去的某个时间,我的条件变量的阻塞时间将远远超过我的预期。例如,如果我希望我的条件变量在1秒后超时,如果有人在等待期间将时钟向后调整10分钟,则条件变量将阻塞10分钟+1秒。我已经确认这是Ubuntu 14.04 LTS系统上的行为

我需要依靠这个超时来至少在某种程度上准确(即,它可能在一定的误差范围内不准确,但如果系统时钟发生变化,仍然需要执行)。看起来我需要做的是编写我自己版本的condition_变量,它使用POSIX函数并使用单调时钟实现相同的接口


这听起来需要做很多工作,而且有点乱。是否有其他解决此问题的方法?

这可能不是最佳解决方案,也不是一个很好的解决方案,但您确实说过“解决”而不是“大量工作”,因此:

  • 使用发行版的工具来监视系统时钟的更改(我不太确定这些工具是什么;最坏的情况是,您可以每5分钟运行一次cron作业,以检查时钟是否在其预期值附近)
  • 在检测到系统时钟变化时,与等待/休眠线程所在的进程进行通信。你可以用一个信号;或者一根管子;或unix域套接字;甚至一些共享内存
  • 在进程端,确保您收到此消息(即,编写一个信号处理程序,或让一个线程在管道上阻塞i/O;或分别使用非
    std::condition_variable
    sleep轮询共享内存)
  • 在收到有关系统时钟更改的通知后,在进程中进行调整,唤醒休眠线程,并根据更改的时间重新评估需要执行的操作。也许它与以前完全相同,在这种情况下,您只需让线程再次使用条件变量

不是很优雅,而且涉及大量开销-但这是有道理的,不是什么疯狂的攻击。

集中注册活动条件变量

做一些努力来检测时钟错误,即使它是当前时钟上的线程旋转锁定(ick)或其他方式

当检测到时钟错误时,拨动条件变量

现在,将您的条件变量包装在一个薄包装器中,该包装器还支持检测时钟滑动。它调用
wait_,直到
,但将谓词替换为检测时钟打滑的谓词,并在发生这种情况时中断等待


当您的实现被破坏时,您必须做您必须做的事情。

在考虑了这个问题的可能解决方案之后,最有意义的一个似乎是禁止使用std::condition_变量(或者至少要明确说明它将始终使用系统时钟)。然后我必须基本上自己重新实现标准库的condition_变量,以尊重时钟选择的方式

由于我必须支持多个平台(Bionic、POSIX、Windows,最终还有MacOS),这意味着我将维护此代码的多个版本


虽然这是令人讨厌的,但替代方案似乎更令人讨厌

我遇到了同样的问题。我的一位同事给了我一个建议,让我改用
中的某些C函数,这对我来说效果非常好

例如,我有:

std::mutex m_dataAccessMutex;
std::condition_variable m_dataAvailableCondition;
其标准用法如下:

std::unique_lock<std::mutex> _(m_dataAccessMutex);
// ...
m_dataAvailableCondition.notify_all();
// ...
m_dataAvailableCondition.wait_for(...); 

检查增压规格?@Swift FridayPie Boost显然存在此问题,并在1.60/1.61左右修复。但是,在这种情况下,我不能使用Boost。我可以复制它们的实现,但如果可以避免的话,我真的不想提供和维护我自己的条件变量的实现。这是图书馆的工作,这绝对是解决这个问题的糟糕办法。更糟糕的是,这个问题还有其他可能的解决办法。
#include <pthread.h>

// Declare the necessary variables
pthread_mutex_t m_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_condattr_t m_attr;
pthread_cond_t m_cond;

// Set clock to monotonic
pthread_condattr_init(&m_attr);
pthread_condattr_setclock(&m_attr, CLOCK_MONOTONIC);
pthread_cond_init(&m_cond, &m_attr); 

// Wait on data
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
ts.tv_sec += timout_in_seconds; 
pthread_mutex_lock(&m_mutex);
int rc = pthread_cond_timedwait(&m_cond, &m_mutex, &ts);
if (rc != ETIMEDOUT)
    ; // do things with data
else 
    ; // error: timeout
// ...
pthread_mutex_unlock(&m_mutex); // have to do it manually to unlock
// ...

// Notify the data is ready
pthread_cond_broadcast(&m_cond);