我遇到了一个奇怪的问题。我有以下代码:
dbg("condwait: timeout = %d, %d\n",
abs_timeout->tv_sec, abs_timeout->tv_nsec);
ret = pthread_cond_timedwait( &q->q_cond, &q->q_mtx, abs_timeout );
if (ret == ETIMEDOUT)
{
dbg("cond timed out\n");
return -ETIMEDOUT;
}
dbg
在每一行之前调用gettimeofday
,并在行前加上时间。它产生以下输出:
7.991151: condwait: timeout = 5, 705032704
7.991158: cond timed out
如您所见,两条调试行之间仅传递了7微秒,但pthread_cond_timedwait
返回ETIMEDOUT
。怎么会发生这种情况?我甚至尝试在初始化cond变量时将时钟设置为其他内容:
int ret;
ret = pthread_condattr_init(&attributes);
if (ret != 0) printf("CONDATTR INIT FAILED: %d\n", ret);
ret = pthread_condattr_setclock(&attributes, CLOCK_REALTIME);
if (ret != 0) printf("SETCLOCK FAILED: %d\n", ret);
ret = pthread_cond_init( &q->q_cond, &attributes );
if (ret != 0) printf("COND INIT FAILED: %d\n", ret);
(没有打印出任何错误消息)。我尝试了CLOCK_REALTIME
和CLOCK_MONOTONIC
。
此代码是阻塞队列的一部分。我需要这样的功能,如果在5秒内没有任何东西放在这个队列上,就会发生其他事情。互斥锁和cond都被初始化,因为如果我不使用pthread_cond_timedwait
,阻塞队列就可以正常工作。
答案 0 :(得分:14)
pthread_cond_timedwait需要绝对时间,而不是相对时间。您需要通过将当前时间添加到超时值来使您的等待时间绝对。
答案 1 :(得分:8)
timespec
的溢出通常是奇怪超时的罪魁祸首
检查 EINVAL:
void timespec_add(struct timespec* a, struct timespec* b, struct timespec* out)
{
time_t sec = a->tv_sec + b->tv_sec;
long nsec = a->tv_nsec + b->tv_nsec;
sec += nsec / 1000000000L;
nsec = nsec % 1000000000L;
out->tv_sec = sec;
out->tv_nsec = nsec;
}
答案 2 :(得分:3)
条件变量可以虚假地解除阻塞。您需要在循环中检查它并每次检查条件。您可能还需要更新超时值。
我找到了pthread_cond_timedwait
here的一些文档。
在那里使用条件变量时 始终是布尔谓词 涉及共享变量 每个条件等待都是真的 如果线程应该继续。伪 从中醒来 pthread_cond_timedwait()或 pthread_cond_wait()函数可以 发生。自从归来 pthread_cond_timedwait()或 pthread_cond_wait()并不意味着 关于这个价值的任何事情 谓词,谓词应该是 在返回时重新评估。
答案 3 :(得分:0)
正如提到的其他答案中一样,你必须使用绝对时间。自C11起,您可以使用timespec_get()
。
struct timespec time;
timespec_get(&time, TIME_UTC);
time.tv_sec += 5;
pthread_cond_timedwait(&cond, &mutex, &time);