pthread_cond_timedwait с таймером моноли c иногда тайм-ауты позже ожидаемого - PullRequest
0 голосов
/ 09 января 2020

Я использую pthread_cond_timedwait с таймером монолити c. Я хотел бы спросить, есть ли какая-то проблема в моем примере или по какой причине, когда иногда pthread_cond_timedwait ожидает дольше, чем указано время ожидания (например, 300 мс).

Спасибо

Пример следует:

#include <pthread.h>
#include <iostream>
#include <ctime>

pthread_cond_t cond;
pthread_condattr_t cond_attr;
pthread_mutex_t mutex;

void *thread1(void *attr)
{
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    //fprintf(stderr, "starting timer for %ds, %dms\n", (period/1000), (period % 1000));

    auto period = 300;
    auto sec = (period / 1000);
    auto nsec = (period % 1000) * 1000000;
    fprintf(stderr, "[start] ts.sec=%d ts.ns = %d\n", ts.tv_sec, ts.tv_nsec);
    if ((ts.tv_nsec + nsec) > 999999999)
    {
        ts.tv_sec += sec + 1;
        ts.tv_nsec = nsec - (1000000000 - ts.tv_nsec);
        fprintf(stderr, "[expected end] ts.sec=%d ts.ns = %d\n", ts.tv_sec, ts.tv_nsec);
        //fprintf(stderr, "timeout = %dms\n", (sec * 1000) + ((1000000000 - ts_now.tv_nsec + ts.tv_nsec)/1000000));
    }
    else
    {
        ts.tv_sec += sec;
        ts.tv_nsec += nsec;
        fprintf(stderr, "[expected end] ts.sec=%d ts.ns = %d\n", ts.tv_sec, ts.tv_nsec);
        //fprintf(stderr, "timeout = %dms\n", (sec * 1000) + ((ts.tv_nsec - ts_now.tv_nsec) / 1000000));
    }
    while (true)
    {
        auto ret = pthread_cond_timedwait(&cond, &mutex, &ts);
        if (ret == ETIMEDOUT)
        {
            struct timespec ts2;
            clock_gettime(CLOCK_MONOTONIC, &ts2);

            fprintf(stderr, "[end] ts.sec=%d ts.ns = %d\n", ts2.tv_sec, ts2.tv_nsec);
            auto seconds = ts2.tv_sec - ts.tv_sec;
            auto nseconds = ts2.tv_nsec - ts.tv_nsec;
            if (nseconds < 0)
            {
                seconds--;
                nseconds = 1000000000 - nseconds;
            }
            fprintf(stderr, "[end] diff = %dms\n", (seconds * 1000) + (nseconds / 1000000));
            break;
        }
        if (ret != 0)
        {
            fprintf(stderr, "ret: %m\n");
        }
    }
    return nullptr;
}

    int main()
{
    pthread_t tid1;

    pthread_mutex_init(&mutex, nullptr);
    pthread_condattr_init(&cond_attr);
    pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
    pthread_cond_init(&cond, &cond_attr);

    pthread_create(&tid1, nullptr, thread1, nullptr);

    pthread_join(tid1, nullptr);

    return 0;
}

для компиляции: g ++ -std = c ++ 11 main. cpp -lpthread

вывод:

dev@ pthread $./a.out
[start] ts.sec=58842 ts.ns = 602310036
[expected end]: ts.sec=58842 ts.ns = 902310036
[end] ts.sec=58842 ts.ns = 903171492
[end] diff = 0ms
dev@ pthread $./a.out
[start] ts.sec=58844 ts.ns = 378002207
[expected end]: ts.sec=58844 ts.ns = 678002207
[end] ts.sec=58844 ts.ns = 799322723
[end] diff = 121ms

1 Ответ

2 голосов
/ 09 января 2020

Вы вызываете неопределенное поведение, вызывая pthread_cond_timedwait() без блокировки связанного мьютекса.

Документация POSIX для pthread_cond_timedwait() сообщает:

ОПИСАНИЕ

Функции pthread_cond_timedwait() и pthread_cond_wait() должны блокировать переменную условия. Приложение должно гарантировать, что эти функции вызываются с mutex, заблокированным вызывающим потоком; в противном случае возникает ошибка (для PTHREAD_MUTEX_ERRORCHECK и надежных мьютексов) или неопределенное поведение (для других мьютексов).

Любые проблемы с синхронизацией могут легко быть результатом "странности" из-за этого неопределенного поведения.

И, как отмечено в комментариях, нет никакой гарантии, как быстро произойдет возврат ошибки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...