c++ - 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
解决方案
您通过调用pthread_cond_timedwait()
而不锁定关联的互斥锁来调用未定义的行为。
状态的POSIX 文档pthread_cond_timedwait()
:
描述
pthread_cond_timedwait()
andpthread_cond_wait()
函数应阻塞条件变量。应用程序应确保这些函数被mutex
调用线程锁定调用;否则,将导致错误(对于PTHREAD_MUTEX_ERRORCHECK
健壮的互斥锁)或未定义的行为(对于其他互斥锁)。
任何时间问题都可能很容易成为这种未定义行为的“奇怪”结果。
正如评论中所指出的,不能保证错误返回的速度有多快。
推荐阅读
- c# - WinForm 元素数组
- tesselation - 六边形和三角形镶嵌的伪希尔伯特曲线等价物是什么?
- sql - asp.net sql删除datatable生成的一行
- rxjs - 如何更改 Single 的状态
以反应的方式对象? - sql - 检索包含列组合的所有表名
- unit-testing - 使用 Gomock 进行测试返回错误:预期调用已被调用最大次数
- java - 列表
覆盖 toArray 最终为 T1[] toArray - firebase - Vue.js Vuex Firebase - 无法理解为什么商店数据在浏览器重新加载页面上不可用
- apache-spark - Spark 2.3的Spark SQL执行计划太慢
- java - 如何将以下日期格式“2013 年 5 月 1 日”转换为“2013-05-01”