首页 > 解决方案 > pthread_cond_timedwait 与 monolic 计时器有时超时比预期晚

问题描述

我将 pthread_cond_timedwait 与单片定时器一起使用。我想问一下我的示例中是否存在问题或者是什么原因,有时 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

标签: c++pthreads

解决方案


您通过调用pthread_cond_timedwait()而不锁定关联的互斥锁来调用未定义的行为。

状态的POSIX 文档pthread_cond_timedwait()

描述

pthread_cond_timedwait()andpthread_cond_wait()函数应阻塞条件变量。应用程序应确保这些函数被mutex调用线程锁定调用;否则,将导致错误(对于PTHREAD_MUTEX_ERRORCHECK健壮的互斥锁)或未定义的行为(对于其他互斥锁)。

任何时间问题都可能很容易成为这种未定义行为的“奇怪”结果。

正如评论中所指出的,不能保证错误返回的速度有多快。


推荐阅读