正确实施condition_variable timed_wait
Implementing condition_variable timed_wait correctly
我正在阅读我的 STL 实现(标准问题 g++ 4.6.2
),并在 condition_variable
中遇到了以下竞争条件:
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);
}
因为__clock_t
是一个std::chrono::system_clock
,我们被NTP之类的东西所束缚(如果时钟在__clock_t::now() + __rtime
后向后移动一天,那么我们将等待一天)。
C++标准(30.5.1)似乎做对了:
26
效果:仿佛
return wait_until(lock, chrono::steady_clock::now() + rel_time);
Boost的condition_variable
实现也有同样的问题:
template<typename duration_type>
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
{
return timed_wait(m,get_system_time()+wait_duration);
}
事实上,底层的 pthreads 实现似乎是问题所在:
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);
因为abstime
被指定为"系统时间",而不是单调时钟。
所以我的问题是:如何正确实现像std::condition_variable::wait_for
这样的东西?是否有现有的实现可以做到这一点?还是我错过了什么?
诀窍
是使用pthread_condattr_setclock
告诉pthread_condattr_t
使用CLOCK_MONOTONIC
。执行此操作的 C 代码非常简单:
#include <time.h>
#include <pthread.h>
#include <errno.h>
#include <stdio.h>
int main()
{
// Set the clock to be CLOCK_MONOTONIC
pthread_condattr_t attr;
pthread_condattr_init(&attr);
if (int err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC))
{
printf("Error setting clock: %dn", err);
}
// Now we can initialize the pthreads objects with that condattr
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond;
pthread_cond_init(&cond, &attr);
// when getting the time, we must poll from CLOCK_MONOTONIC
struct timespec timeout;
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
timeout.tv_sec = now.tv_sec + 5;
timeout.tv_nsec = now.tv_nsec;
// business as usual...
pthread_mutex_lock(&mutex);
int rc = pthread_cond_timedwait(&cond, &mutex, &timeout);
if (rc == ETIMEDOUT)
printf("Success!n");
else
printf("Got return that wasn't timeout: %dn", rc);
pthread_mutex_unlock(&mutex);
return 0;
}
我将暂时保持开放状态,因为有人可能会有更简单的答案。我在这里不满意的是,这意味着wait_until
很难用实时时钟实现(我最好的解决方案是将time_point
中提供的Clock
转换为steady_clock
的时间,然后从那里开始......它仍然受时间变化竞争条件的影响,但如果你实时指定超时,你已经犯了一个可怕的错误)。
相关文章:
- std::condition_variable::wait()如何评估给定的谓词
- C++ Singleton - Prevent ::instance() to variable
- std::atomic和std::condition_variable wait,notify_*方法之间的区别
- std::memory_order for std::atomic:<T>:wait
- 如何通过多类"Union variable" (sfml) 使用轮询事件
- 将成员函数作为构造函数参数调用时出错 "Variable is not a type name"
- std::p romise::set_value() 和 std::future::wait() 是否提供内存围栏?
- 为什么我会收到"Run-Time Check Failure #2 - Stack around the variable 'pr' was corrupted"错误?
- C++:寻找"returning address of local variable..."的更正
- C++ - 在我尝试制作一个简单的计算器时有一个"uninitialized local variable y used"警告
- 对于等待以 std::future wait() 返回的函数的 CPU 使用率或检查标志在循环中休眠一段时间哪个更好?
- Visual Studio Code "variable " u8 的 C/C++ 扩展名 " " 不是类型名称"
- C++ "Using Uninitialized Memory.. (variable name) "
- cudaMallocManaged for host-initiated variable
- Cppcheck "Reference to auto variable returned"失败的原因?
- std::future::get()或std::future::wait()是std::thread::join()的替
- OpenCV 和 C++:"Can't resolve variable 'Mat`"
- 是否有用于"go to variable type definition" C++中"auto"变量的 Visual Studio 键盘快捷方式?
- 冲刺错误"variable may be unsafe" (C4996)...选择?
- Visual Studio生成"Error: uninitialized local variable 'x' "而在线编译器不会 - 为什么?