受上一跳秒的启发,我一直在使用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
,但在mac上,它只能使用实时时钟,因此当系统时钟设置或发生闰秒时,它会出现错误行为。
是否缺少API?在类unix系统上是否有一种合理的可移植方法来创建性能良好的间隔计时器,或者这总结了当今的情况?
我指的是行为端正,携带方便,我的意思是:
不易发生时钟偏差(当然,减去系统时钟自身的偏差)
对正在设置的系统时钟或发生的闰秒具有弹性
能够在同一进程中支持多个计时器
至少在Linux、Mac OS X和FreeBSD上可用
关于闰秒的说明(针对R..'s answer):
POSIX的天数正好是86400秒长,但现实世界中的天数很少会更长或更短。系统如何解决这种差异是由实现定义的,但闰秒与前一秒共享相同的unix时间戳是常见的。另请参见:Leap Seconds and What To Do With Them。
Linux内核leap second错误是由于在将时钟设置回秒后未能执行内务管理:https://lkml.org/lkml/2012/7/1/203。即使没有那个窃听器,时钟也会向后跳一秒钟。
最佳答案
posix计时器(timer_create
)不需要信号;您还可以通过SIGEV_THREAD
通知类型在线程中安排计时器过期。不幸的是,glibc的实现实际上为每个过期创建了一个新线程(这两个线程都有很多开销,并且破坏了实时质量健壮性的任何希望),尽管标准允许在每个过期时重用同一个线程。
除此之外,我建议您创建自己的线程,使用clock_nanosleep
和TIMER_ABSTIME
作为间隔计时器。由于您提到一些损坏的系统可能缺少这些接口,您可以在这些系统上简单地减少实现(例如基于CLOCK_MONOTONIC
),并认为由于缺乏单调时钟,它可能质量较低,但这只是使用像macosx这样的低质量实现的一个基本限制。
至于你对闰秒的担心,如果ntpd或类似的程序在闰秒发生时使你的实时时钟向后跳,那是ntpd中的一个严重错误。POSIX时间(从纪元开始的秒数)是以日历秒(确切地说是一天的1/86400)为单位的,而不是以国际单位秒为单位的,因此,在POSIX系统(如果有的话)上,闰秒逻辑唯一属于pthread_cond_timedwait
/mktime
/gmtime
的地方是当它们在localtime
和故障时间之间转换时。我没有跟踪这次遇到的错误,但它们似乎是由于系统软件做了很多愚蠢和错误的事情,而不是根本问题造成的。
关于c - 是否有行为良好的POSIX间隔计时器?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11338899/