linux下1ms分辨率定时器推荐的方法

我需要一个在linux下1ms分辨率的计时器。 它用来增加一个定时器的值,这个定时器的值又被用来查看是否应该触发不同的事件。 由于glibc的要求,POSIX timerfd_create不是一个选项。 我试过timer_create和timer_settimer,但是我最好从他们得到的是一个10毫秒的分辨率,较小的值似乎默认为10毫秒的分辨率。 根据手册页,Getittimer和setitimer的分辨率为10毫秒。

做这个计时器的唯一方法,我现在可以想到的是在我的主循环中使用clock_gettime和CLOCK_MONOTONIC来testing一个ms是否已经通过,如果是的话增加计数器(然后检查各个事件是否应该触发)。

有没有比在主循环中不断查询更好的方法? 什么是推荐的解决scheme?

我正在使用的语言是普通的老c

更新
我正在使用2.6.26内核。 我知道你可以让它在1kHz中断,然后POSIX timer_ *function可以被编程到1ms,但这似乎不是可靠的,我不想使用它,因为它可能需要一个新的内核系统。 一些库存核心似乎仍然有100Hzconfiguration。 我需要检测到这一点。 该应用程序可能运行在别的东西比我的系统:)

我不能睡1ms,因为可能有networking事件,我必须作出反应。

我如何解决它由于这不是那么重要,我只是宣布全局计时器有一个100毫秒的分辨率。 所有使用自己的定时器的事件必须设置至less100ms的定时器到期。 我或多或less想知道是否会有更好的办法,因此也就是这个问题。

为什么我接受了答案我认为freespace的答案最好的描述了为什么没有实时的Linux系统是不可能的。

Solutions Collecting From Web of "linux下1ms分辨率定时器推荐的方法"

在主循环中轮询也不是一个答案 – 你的进程可能没有太多的CPU时间,所以在代码运行之前超过10ms将会消失,使得它没有任何意义。

对于大多数非实时操作系统 (RTOS),10ms是标准的定时器分辨率。 但是在非RTOS中是没有实际意义的 – 调度程序和调度程序的行为将会极大地影响您响应计时器到期的速度。 例如,即使假设您有一个10ms的分辨率计时器,如果您的代码没有运行,您也无法响应计时器到期。 由于无法预测代码何时运行,因此无法准确响应计时器到期。

当然有实时的Linux内核,请参阅http://www.linuxdevices.com/articles/AT8073314981.html获取列表。 实时操作系统提供的功能可以让你在代码运行时得到软或硬的保证。 这是对可靠和准确地响应计时器到期等的唯一方法。

获得1ms分辨率的定时器可以完成libevent的工作。

把你的定时器组织成一个小堆 ,也就是堆顶部是最早到期(绝对)时间的定时器(一个rb-tree也可以工作,但有更多的开销)。 在主要事件循环中调用select()epoll() ,计算最早定时器的到期时间与现在之间的增量(以毫秒为单位)。 使用此增量作为select()的超时。 select()epoll()超时具有1ms的分辨率。

我有一个定时器解析测试,使用上面解释的机制(但不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。

我不确定这是否是最好的解决方案,但是您可以考虑编写一个使用内核高分辨率定时器的小内核模块来进行计时。 基本上,你会创建一个设备文件的读取只会返回1毫秒的时间间隔。

Asterisk PBX通过ztdummy模块使用这种方法的一个例子。 如果你的谷歌ZTDILY你可以找到这样做的代码。

我认为即使在主循环中不断的查询,你也会遇到在标准Linux上实现1 ms精度的问题,因为内核并不能保证你的应用程序总能得到CPU。 例如,由于抢先式多任务处理,你可以睡几十毫秒,而且你可以做的事情很少。

你可能想看看实时Linux 。

我似乎记得gettimeofday /基于usleep的轮询可以得到好的结果 – 我不需要1000秒的定时器或者其他任何东西,但是我需要精确的时钟来满足我需要的时钟 – 我的应用程序是一个MIDI鼓机器控制器,我似乎记得如果你不希望它听起来像一个非常糟糕的鼓手(尤其是计算MIDI的内置延迟),你需要一个鼓机所需的亚毫秒精度–iirc(这是2005年,所以我的记忆有点模糊)我在200微秒的目标时间与睡着了。

但是,我没有在系统上运行其他任何东西。 如果你有一个受控制的环境,你可能会得到这样的解决方案。 如果有更多的系统正在运行(看cron启动updatedb等),那么事情可能会崩溃。

如果您的目标是x86平台,您应该检查HPET定时器。 这是高精度的硬件计时器。 它必须得到你的母亲的支持(现在所有人都支持它),你的内核也应该包含驱动程序。 我已经使用了它几次没有任何问题,能够达到比1毫秒好得多的分辨率。

这里是一些文档和例子:

你在Linux 2.4内核上运行吗?

从VMware知识库文章#1420( http://kb.vmware.com/kb/1420 )。

Linux客户操作系统通过计数定时器中断来保持时间。 未修补的2.4及更早版本的内核编程虚拟系统定时器,以100Hz(每秒100个中断)请求时钟中断。 另一方面,2.6内核在1000Hz时请求中断 – 十倍频率。 由发行商修改的一些2.4内核包含2.6特性,也要求1000Hz中断,或者在某些情况下,以其他速率(如512Hz)中断。

首先,获取内核源代码并使用调整后的HZ参数进行编译。

  • 如果HZ=1000 ,定时器每秒中断1000次。 对于i386机器可以使用HZ=1000
  • 在嵌入式机器上,HZ可能被限制为100或200。

为了良好的操作,应该打开PREEMPT_KERNEL选项。 有内核不正确地支持这个选项。 你可以通过搜索检查出来。

最近的内核,例如2.6.35.10,支持NO_HZ选项,打开动态报价。 这意味着在闲置时不会有计时器滴答声,但是在指定的时刻会产生计时器滴答声。

内核有一个RT补丁,但硬件支持非常有限。

一般来说,RTAI对于您的问题是一个全面的杀手解决方案,但其硬件支持非常有限。 但是,好的CNC控制器,如emc2,使用RTAI进行计时,可能是5000赫兹,但安装它可能很难。

如果可以的话,你可以添加硬件来产生脉冲。 这将使一个系统可以适应任何操作系统版本。

你至少可以在你的循环中使用nanosleep睡1ms吗? 或者是一个glibc的东西?

更新:没关系,我从手册页看到“最多可能比指定的时间长10 ms,直到进程再次运行”

您不需要一个简单的实时应用程序的RTOS。 所有现代处理器都具有通用定时器。 获取你正在处理的任何目标CPU的数据表。 查看内核源代码,在arch目录下,您将找到处理器特定的源代码如何处理这些定时器。

你可以采取两种方法:

1)你的应用程序只运行你的状态机,没有别的。 Linux只是你的“启动加载器”。 创建一个安装字符设备的内核对象。 在插入到内核中时,设置你的GP定时器连续运行。 你知道它运行的频率。 现在,在内核中,显式地禁用你的看门狗。 现在禁用中断(硬件和软件)在一个单一的cpu Linux内核上,调用spin_lock()将完成这个任务(永远不要放弃它).CPU是你的。 忙碌循环,检查GPT的值,直到所需的滴答数已经超过,当它们有时,为下一个超时设置一个值并进入处理循环。 只要确保你的代码的爆发时间在1ms以下

2)第二个选项。 这假定你正在运行一个抢先的Linux内核。 在运行的操作系统旁边设置一个未使用的GPT。 现在,设置一个中断来触发一些可配置的余量,在你的1ms超时发生之前(比如说50-75微秒)。当中断触发时,你将立即禁止中断并旋转等待1ms窗口,然后进入你的状态机,在等待OUT时启用中断。 这说明了你正在内核中与其他东西合作,禁止中断。 这假设没有其他内核活动可以长时间锁定中断(超过100us)。现在,您可以测量触发事件的准确性并使窗口变大,直到满足您的需要。

相反,如果您正在尝试学习RTOS的工作方式……或者如果您试图通过多个实时责任来解决控制问题,那么请使用RTOS。

使用“/ dev / rtc0”(或“/ dev / rtc”)设备及其相关的ioctl()接口怎么样? 我想它提供了一个准确的计时器计数器。 不可能将速率设置为1ms,而是将其设置为近似值或1 / 1024sec(1024Hz)或更高的频率(如8192Hz)。