Tra*_*kel 12 c++ time multithreading
我正在阅读我的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);
}
Run Code Online (Sandbox Code Playgroud)
因为__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);
}
Run Code Online (Sandbox Code Playgroud)
实际上,底层的pthreads实现似乎是问题所在:
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);
Run Code Online (Sandbox Code Playgroud)
因为abstime
被指定为"系统时间",而不是单调时钟.
所以我的问题是:如何才能std::condition_variable::wait_for
正确实现?是否有现成的实现可以做到这一点?或者我错过了什么?
诀窍是使用a 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: %d\n", 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: %d\n", rc);
pthread_mutex_unlock(&mutex);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我打算暂时离开,因为有人可能会有一个更简单的答案.我对此不满意的是,它意味着wait_until
使用实时时钟实现起来相当困难(我最好的解决方案是将提供Clock
的time_point
转换为steady_clock
时间并从那里开始...它仍然受到时间变化竞争条件的影响,但如果你实时指定超时,那你就已经犯了一个可怕的错误.