pthread_cond_timedwait возвращается немедленно
-
20-08-2019 - |
Вопрос
У меня возникла странная проблема.У меня есть следующий код:
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
.Как это могло произойти?Я даже попытался установить clock на что-то другое при инициализации переменной 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
.
Решение
pthread_cond_timedwait занимает абсолютное время, а не относительное.Вам нужно сделать ваше время ожидания абсолютным, добавив к текущему времени значение вашего тайм-аута.
Другие советы
Переполнение в timespec
обычно является виновником странных тайм-аутов.
Проверьте наличие ЭЙНВАЛ:
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;
}
Переменная условия может быть обманным путем разблокирована.Вам нужно проверить это в цикле и проверять условие каждый раз до конца.Вероятно, вам также потребуется обновить значение таймаута.
Я нашел кое-какую документацию для pthread_cond_timedwait
здесь.
При использовании переменных условия всегда есть логический предикат включающий общие переменные, связанные с каждым условием ожидание, которое является истинным если поток должен продолжаться.Ложные пробуждения от функций pthread_cond_timedwait() или pthread_cond_wait() могут возникать.Поскольку возврат из pthread_cond_timedwait() или pthread_cond_wait() не подразумевает ничего о значении этого предикат, предикат должен быть переоценен при таком возврате.
Как уже упоминалось в других ответах, вы должны использовать абсолютное время.Начиная с C11 вы можете использовать timespec_get()
.
struct timespec time;
timespec_get(&time, TIME_UTC);
time.tv_sec += 5;
pthread_cond_timedwait(&cond, &mutex, &time);