受到最后一个闰秒的启发,我一直在探索使用POSIX调用的计时(特别是间隔计时器).
POSIX提供了几种设置计时器的方法,但它们都有问题:
sleep并且nanosleep这些在被信号中断后重新启动很烦人,并引入了时钟偏差.您可以通过一些额外的工作来避免一些但不是全部的这种偏差,但这些功能使用实时时钟,所以这并非没有陷阱.setitimer或者更现代的timer_settime这些被设计为间隔计时器,但它们是每个进程,如果您需要多个活动计时器,这是一个问题.它们也不能同步使用,但这不是什么大问题.clock_gettime并且clock_nanosleep在使用时看起来像是正确的答案CLOCK_MONOTONIC.clock_nanosleep支持绝对超时,因此您可以只是睡眠,增加超时,然后重复.在中断之后也很容易重启.不幸的是,这些功能可能也是特定于Linux的:在Mac OS X或FreeBSD上不支持它们.pthread_cond_timedwait可以在Mac上使用,可以gettimeofday作为一个kludgy解决方案,但在Mac上它只能与实时时钟一起使用,因此当系统时钟设置或闰秒发生时,它会受到不当行为的影响.我缺少一个API吗?是否有一种合理的可移植方式在类UNIX系统上创建性能良好的间隔定时器,或者这总结了今天的状态?
通过良好的行为和合理的便携性,我的意思是:
关于闰秒的注释(响应R ..的回答):
POSIX天的长度恰好是86,400秒,但现实世界的日子很少会更长或更短.系统如何解决这种差异是由实现定义的,但闰秒通常与前一秒共享相同的UNIX时间戳.另请参见:闰秒以及如何处理它们.
Linux内核闰第二个错误是在将时钟设置为秒后无法进行内务处理的结果:https://lkml.org/lkml/2012/7/1/203.即使没有那个错误,时钟也会向后跳一秒钟.
为什么在调用之前需要锁定互斥锁pthread_cond_wait?
另外,在调用之前是否需要锁定(在同一个互斥锁上)pthread_cond_signal?
谢谢你的帮助.
void WorkHandler::addWork(Work* w){
printf("WorkHandler::insertWork Thread, insertWork locking \n");
lock();
printf("WorkHandler::insertWork Locked, and inserting into queue \n");
m_workQueue.push(w);
signal();
unLock();
}
Run Code Online (Sandbox Code Playgroud)
我按照教程,得到了这个.我想知道是否可以像这样更改singal()和unLock()的顺序
void WorkHandler::addWork(Work* w){
printf("WorkHandler::insertWork Thread, insertWork locking \n");
lock();
printf("WorkHandler::insertWork Locked, and inserting into queue \n");
m_workQueue.push(w);
unLock();
signal();
}
Run Code Online (Sandbox Code Playgroud)
如果我不能这样做,你能否详细说明为什么我不允许这样做?提前致谢.
请考虑以下示例.目标是使用两个线程,一个用于"计算"一个值,另一个用于消耗和使用计算值(我试图简化这个).计算线程通过使用条件变量向另一个线程发信号通知该值已经计算并准备就绪,之后等待线程消耗该值.
// Hopefully this is free from errors, if not, please point them out so I can fix
// them and we can focus on the main question
#include <pthread.h>
#include <stdio.h>
// The data passed to each thread. These could just be global variables.
typedef struct ThreadData
{
pthread_mutex_t mutex;
pthread_cond_t cond;
int spaceHit;
} ThreadData;
// The "computing" thread... just asks you to press space and checks if you did or not
void* getValue(void* td)
{
ThreadData* data …Run Code Online (Sandbox Code Playgroud) 如您所知,应该在循环中调用条件变量以避免虚假唤醒.像这样:
while (not condition)
condvar.wait();
Run Code Online (Sandbox Code Playgroud)
如果另一个线程想要唤醒等待线程,则必须将condition标志设置为true.例如:
condition = true;
condvar.notify_one();
Run Code Online (Sandbox Code Playgroud)
我想知道,这种情况是否有可能阻止条件变量:
1)等待线程检查条件标志,发现它等于FALSE,因此,它将进入condvar.wait()例程.
2)但就在此之前(但是在条件标志检查之后)等待线程被内核抢占(例如,因为时隙到期).
3)此时,另一个线程想要通知等待线程有关条件.它将条件标志设置为TRUE并调用condvar.notify_one();
4)当内核调度程序再次运行第一个线程时,它进入condvar.wait()例行程序,但通知已经丢失.
因此,等待线程无法退出condvar.wait(),尽管条件标志设置为TRUE,因为不再有唤醒通知.
可能吗?
假设某些条件变量"cond"与互斥变量"mutex"相关联.如果线程cond在调用后处于休眠状态pthread_cond_wait(&cond,&mutex),并且另一个已mutex锁定的线程已完成,则该线程在调用pthread_cond_signal(&cond)之前或之后调用pthread_mutex_unlock(&mutex)是否重要?它是否甚至需要解锁互斥锁pthread_cond_signal(&cond),因为睡眠线程无论如何都会获取互斥锁?
编辑:根据https://computing.llnl.gov/tutorials/pthreads/#ConVarOverview,"调用pthread_cond_signal()后未能解锁互斥锁可能不允许匹配的pthread_cond_wait()例程完成(它将保持阻塞状态). " 我想那时,解锁,也许只是之后才需要.