我需要在linux下以1ms的分辨率打开计时器.它用于递增计时器值,而计时器值又用于查看是否应触发各种事件.由于glibc要求,POSIX timerfd_create不是一个选项.我尝试过timer_create和timer_settimer,但我从它们得到的最好的是10ms的分辨率,较小的值似乎默认为10ms的分辨率.根据联机帮助页,Getittimer和setitimer的分辨率为10毫秒.
我现在可以想到的唯一一种做这个计时器的方法是在我的主循环中使用带有CLOCK_MONOTONIC的clock_gettime,如果ms已经通过则测试,如果是,则增加计数器(然后检查是否应该触发各种事件).
有没有比在主循环中不断查询更好的方法呢?推荐的解决方案是什么?
我使用的语言很简单
更新
我使用的是2.6.26内核.我知道你可以在1kHz时中断它,然后POSIX timer_*函数可以编程为1ms,但这似乎不可靠,我不想使用它,因为它可能需要一些新内核系统.一些库存内核似乎仍然配置了100Hz.我需要检测到这一点.该应用程序可能运行在我的系统以外的其他东西:)
我无法入睡1ms因为可能有网络事件我必须做出反应.
我如何解决它 因为它并不重要我只是宣称全局计时器的分辨率为100ms.使用自己的计时器的所有事件必须设置至少100毫秒的计时器到期.我或多或少想知道是否会有更好的方法,因此问题.
为什么我接受了答案 我认为自由空间的答案最好地描述了为什么没有实时Linux系统它是不可能的.
要获得1ms的分辨率计时器,请执行libevent所做的事情.
将您的计时器组织到一个最小堆中,也就是说,堆的顶部是具有最早到期(绝对)时间的计时器(rb-tree也可以工作但具有更多的开销).在调用之前select()
或epoll()
在主事件循环中计算最早计时器到现在的到期时间之间的增量(以毫秒为单位).使用此增量作为超时select()
.select()
和epoll()
超时有1毫秒的分辨率.
我有一个定时器分辨率测试,它使用上面解释的机制(但不是libevent).该测试测量所需的定时器到期时间与1ms,5ms和10ms定时器的实际到期之间的差异:
1000 deviation samples of 1msec timer: min= -246115nsec max= 1143471nsec median= -70775nsec avg= 901nsec stddev= 45570nsec 1000 deviation samples of 5msec timer: min= -265280nsec max= 256260nsec median= -252363nsec avg= -195nsec stddev= 30933nsec 1000 deviation samples of 10msec timer: min= -273119nsec max= 274045nsec median= 103471nsec avg= -179nsec stddev= 31228nsec 1000 deviation samples of 1msec timer: min= -144930nsec max= 1052379nsec median= -109322nsec avg= 1000nsec stddev= 43545nsec 1000 deviation samples of 5msec timer: min= -1229446nsec max= 1230399nsec median= 1222761nsec avg= 724nsec stddev= 254466nsec 1000 deviation samples of 10msec timer: min= -1227580nsec max= 1227734nsec median= 47328nsec avg= 745nsec stddev= 173834nsec 1000 deviation samples of 1msec timer: min= -222672nsec max= 228907nsec median= 63635nsec avg= 22nsec stddev= 29410nsec 1000 deviation samples of 5msec timer: min= -1302808nsec max= 1270006nsec median= 1251949nsec avg= -222nsec stddev= 345944nsec 1000 deviation samples of 10msec timer: min= -1297724nsec max= 1298269nsec median= 1254351nsec avg= -225nsec stddev= 374717nsec
该测试在Fedora 13内核2.6.34上作为实时过程运行,1ms定时器的最佳实现精度为avg = 22nsec stddev = 29410nsec.
主循环中的轮询也不是一个答案 - 您的进程可能没有太多的CPU时间,因此在代码运行之前将超过10毫秒,这使得它没有实际意义.
10ms是大多数非实时操作系统(RTOS)的标准定时器分辨率.但是在非RTOS中没有实际意义 - 调度程序和调度程序的行为将极大地影响您响应计时器到期的速度.例如,即使您有一个10ms的子分辨率计时器,如果您的代码没有运行,也无法响应计时器到期.由于无法预测代码何时运行,因此无法准确响应计时器到期.
当然有实时Linux内核,请参阅http://www.linuxdevices.com/articles/AT8073314981.html获取列表.RTOS提供了一些工具,您可以通过这些工具获得有关何时运行代码的软或硬保证.这是关于可靠和准确地响应定时器到期等的唯一方法.
我不确定它是最好的解决方案,但您可能会考虑编写一个使用内核高分辨率计时器来执行计时的小型内核模块.基本上,您将创建一个设备文件,其读取只会以1毫秒的间隔返回.
通过ztdummy模块在Asterisk PBX中使用了这种方法的一个示例.如果你google for ztdummy,你可以找到执行此操作的代码.
我认为即使在主循环中进行常量查询,您也无法使用标准Linux实现1 ms精度,因为内核无法确保您的应用程序始终获得CPU.例如,由于先发制人的多任务处理,您可以在几十毫秒内进入睡眠状态,而您几乎无能为力.
您可能想要研究实时Linux.