pthread_cond_timedwait возвращается немедленно - PullRequest
7 голосов
/ 19 марта 2009

У меня странная проблема. У меня есть следующий код:

    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.

Ответы [ 4 ]

14 голосов
/ 19 марта 2009

pthread_cond_timedwait занимает абсолютное время, а не относительное время. Вам нужно сделать ваше время ожидания абсолютным, добавив к текущему времени значение времени ожидания.

8 голосов
/ 09 ноября 2012

Переполнение в 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;
}
3 голосов
/ 19 марта 2009

Переменная условия может внезапно разблокироваться. Вы должны проверить это в цикле и проверять состояние каждый раз до конца. Возможно, вам также потребуется обновить значение времени ожидания.

Я нашел некоторую документацию для pthread_cond_timedwait здесь .

При использовании условных переменных всегда логический предикат с участием общих переменных, связанных с каждым условием ожидания, что это правда если поток должен продолжаться. поддельный пробуждения от pthread_cond_timedwait () или Функции pthread_cond_wait () могут происходят. С момента возвращения из pthread_cond_timedwait () или pthread_cond_wait () не подразумевает что-нибудь о значении этого предикат, предикат должен быть переоценка после такого возвращения.

0 голосов
/ 20 марта 2017

Как уже упоминалось в других ответах, вы должны использовать абсолютное время. Начиная с C11 вы можете использовать timespec_get().

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

pthread_cond_timedwait(&cond, &mutex, &time);
...