admin管理员组文章数量:1599541
偶然一次测试的时候发现时间前调时会发现condition_variable.wait_for锁住
目标环境:CentOS7 + gcc9.3
调查发现:
std::condition_variable内部使用的是system_clock,会随着系统时间的变化而变化。
编译使用的stl版本为9,默认的版本是4.8.5,对应的实现如下
stl版本4.8.5
class condition_variable
{
typedef chrono::system_clock __clock_t;
......
}
template<typename _Rep, typename _Period>
cv_status
wait_for(unique_lock<mutex>& __lock,
const chrono::duration<_Rep, _Period>& __rtime)
{ return wait_until(__lock, __clock_t::now() + __rtime); }
stl版本9
class condition_variable
{
typedef chrono::system_clock __clock_t;
typedef chrono::steady_clock __steady_clock_t;
......
}
template<typename _Rep, typename _Period, typename _Predicate>
bool wait_for(unique_lock<mutex>& __lock,
const chrono::duration<_Rep, _Period>& __rtime,
_Predicate __p)
{
using __dur = typename __steady_clock_t::duration;
auto __reltime = chrono::duration_cast<__dur>(__rtime);
if (__reltime < __rtime)
++__reltime;
return wait_until(__lock, __steady_clock_t::now() + __reltime,
std::move(__p));
}
template<typename _Dur>
cv_status __wait_until_impl(unique_lock<mutex>& __lock,
const chrono::time_point<__clock_t, _Dur>& __atime)
{
auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
......
return (__clock_t::now() < __atime
? cv_status::no_timeout : cv_status::timeout);
}
这两个版本中使用的都是system_clock作为计时器,因此时间前调时会出现等待时间超过预期值的问题。
后来又在Windows上试了下,发现VS2019并不存在该问题。
template <class _Rep, class _Period, class _Predicate>
bool wait_for(unique_lock<mutex>& _Lck, const chrono::duration<_Rep, _Period>& _Rel_time, _Predicate _Pred) {
// wait for signal with timeout and check predicate
return _Wait_until1(_Lck, chrono::steady_clock::now() + _Rel_time, _Pred);
}
解决方法:
(一)使用boost的condition_variable
boost在1.60修复了该问题
使用steady_lock,需要在项目中增加宏:BOOST_CHRONO_POSIX_API
备注:增加该宏后会有个编译器的告警提示。可以考虑注释掉该告警boost/chrono/config.hpp
(二)自己实现condition_variable
网络的上的参考代码
参考写法:
#include <pthread.h>
// Declare the necessary variablespthread_mutex_t m_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_condattr_t m_attr;
pthread_cond_t m_cond;
// Set clock to monotonicpthread_condattr_init(&m_attr);
pthread_condattr_setclock(&m_attr, CLOCK_MONOTONIC);
pthread_cond_init(&m_cond, &m_attr);
// Wait on datastruct 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 dataelse
; // error: timeout// ...pthread_mutex_unlock(&m_mutex); // have to do it manually to unlock// ...
// Notify the data is readypthread_cond_broadcast(&m_cond);
(三)升级gcc和glibc
gcc10,提供了稳定递增时间戳的方案
但是其实现依托于pthread_cond_clockwait,目前的CentOS默认的glibc2.17版本不支持
glibc-2.30才支持pthread_cond_clockwait,如图
使用时项目中需要定义宏:_GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT
参考链接:
#11377 (Boost condition variable always waits for system clock deadline) – Boost C++ Libraries
make condition_variable_any steady when BOOST_THREAD_HAS_CONDATTR_SET… · boostorg/thread@8f5de1d · GitHub
c++ - How do I deal with the system clock changing while waiting on a std::condition_variable? - Stack Overflow
本文标签: 线程隐患conditionvariable
版权声明:本文标题:线程同步:condition_variable的隐患 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/xitong/1728322489a1154006.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论