9

我有一个奇怪的问题。我有以下代码:

    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_REALTIMECLOCK_MONOTONIC

此代码是阻塞队列的一部分。我需要这样的功能,如果在 5 秒内没有任何东西放在这个队列上,就会发生其他事情。互斥体和条件都被初始化,因为如果我不使用阻塞队列工作正常pthread_cond_timedwait

4

4 回答 4

16

pthread_cond_timedwait 需要绝对时间,而不是相对时间。您需要通过将当前时间添加到超时值来使您的等待时间成为绝对时间。

于 2009-03-19T03:05:56.070 回答
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;
}
于 2012-11-09T07:07:58.623 回答
4

条件变量可以虚假地解除阻塞。您需要循环检查它并每次检查条件。您可能还需要更新超时值。

pthread_cond_timedwait 我在这里找到了一些文档。

当使用条件变量时,总是有一个布尔谓词涉及与每个条件相关联的共享变量等待如果线程应该继续,则该条件等待为真。可能会发生来自 pthread_cond_timedwait() 或 pthread_cond_wait() 函数的虚假唤醒。由于 pthread_cond_timedwait() 或 pthread_cond_wait() 的返回并不意味着该谓词的任何值,因此应在此类返回时重新评估谓词。

于 2009-03-19T03:07:00.090 回答
1

正如已经在其他答案中提到的那样,您必须使用绝对时间。从 C11 开始,您可以使用timespec_get().

struct timespec time;
timespec_get(&time, TIME_UTC);
time.tv_sec += 5;

pthread_cond_timedwait(&cond, &mutex, &time);
于 2017-03-20T10:48:56.363 回答