<acronym id='dxpbz'><em id='dxpbz'></em><td id='dxpbz'><div id='dxpbz'></div></td></acronym><address id='dxpbz'><big id='dxpbz'><big id='dxpbz'></big><legend id='dxpbz'></legend></big></address>
<i id='dxpbz'></i>

  1. <i id='dxpbz'><div id='dxpbz'><ins id='dxpbz'></ins></div></i>

        <code id='dxpbz'><strong id='dxpbz'></strong></code>
        <ins id='dxpbz'></ins>

          <dl id='dxpbz'></dl>
          <fieldset id='dxpbz'></fieldset><span id='dxpbz'></span>
        1. <tr id='dxpbz'><strong id='dxpbz'></strong><small id='dxpbz'></small><button id='dxpbz'></button><li id='dxpbz'><noscript id='dxpbz'><big id='dxpbz'></big><dt id='dxpbz'></dt></noscript></li></tr><ol id='dxpbz'><table id='dxpbz'><blockquote id='dxpbz'><tbody id='dxpbz'></tbody></blockquote></table></ol><u id='dxpbz'></u><kbd id='dxpbz'><kbd id='dxpbz'></kbd></kbd>
        2. 深入研究Linux高精确时序函数

          • 时间:
          • 浏览:4
          • 来源:124软件资讯网

            首先, 我会说不保证你在使用者模式 (user-mode) 中执行的行程 (process) 能够准确地控制时序由于 Linux 是个多工的作业情况. 你在执行中的行程 (process) 随时会由于种种缘故原由被暂停约莫 10 毫秒到数秒 (在系统负荷很是高的时间). 然而, 对於大多数使用 I/O 埠的应用而言, 这个延迟时间现实上算不了什麽. 要缩短延迟时间, 你得使用函式 nice 将你在执行中的行程 (process ) 设定成高优先权(请参考 nice(2) 使用说明文件) 或使用即时排程法 (real-time scheduling) (请看下面).

              若是你想获得比在一样平常使用者模式 (user-mode) 中执行的行程 (process) 还要准确的时序, 有一些要领可以让你在使用者模式 (user-mode) 中做到 `即时' 排程的支援. Linux 2.x 版本的焦点中有软体方式的即时排程支援; 详细的说明请参考 sched_setscheduler(2) 使用说明文件. 有一个特殊的焦点支援硬体的即时排程;

               (Sleeping) : sleep() 与 usleep()

              现在, 让我们最先较简朴的时序函式呼叫. 想要延迟数秒的时间, 最佳的要领或许 是使用函式 sleep() . 想要延迟至少数十毫秒的时间 (10 ms 似乎已是最短的 延迟时间了), 函式 usleep() 应该可以使用. 这些函式是让出 CPU 的使用权 给其他想要执行的行程 (processes) (``自己休息去了''), 以是没有铺张掉 CPU 的时间. 细节请参考 sleep(3) 与 usleep(3) 的说明文件.

              若是让出 CPU 的使用权因而使得时间延迟了约莫 50 毫秒 (这取决於处置惩罚器与机械的速率, 以及系统的负荷), 就铺张掉 CPU 太多的时间, 由于 Linux 的排程器 (scheduler) (单就 x86 架构而言) 在将控制权发还给你的行程 (process) 之前通常至少要破费 10-30 毫秒的时间. 因此, 短时间的延迟, 使用函式 usleep(3) 所获得的延迟效果通常会大於你在参数所指定的值, 约莫至少有 10 ms.

              nanosleep()

              在 Linux 2.0.x 一系列的焦点刊行版本中, 有一个新的系统呼叫 (system call), nanosleep() (请参考 nanosleep(2) 的说明文件), 他让你能够 休息或延迟一个短的时间 (数微秒或更多).

              若是延迟的时间 <= 2 ms, 若(且唯若)你执行中的行程 (process) 设定了软体的即时 排程 (就是使用函式 tt/sched_setscheduler()/), 呼叫函式 nanosleep() 时 不是使用一个忙碌回圈来延迟时间; 就是会像函式 usleep() 一样让出 CPU 的使用权休息去了.

              这个忙碌回圈使用函式 udelay() (一个驱动程式常会用到的焦点内部的函式) 来告竣, 而且使用 BogoMips 值 (BogoMips 可以准确量测这类忙碌回圈的速率) 来盘算回圈延迟的时间长度. 其怎样行动的细节请参考 /usr/include/asm/delay.h).

              使用 I/O 埠来延迟时间

              另一个延迟数微秒的要领是使用 I/O 埠. 就是从埠位址 0x80 输入或输出任何 byte 的资料 (请参考前面) 等候的时间应该险些只要 1 微秒这要看你的处置惩罚器的型别与速率. 若是要延迟数微秒的时间你可以将这个行动多做频频. 在任何尺度的机械上输出资推测该 埠位址应该不会有不良的後果□对 (而且有些焦点的装备驱动程式也在使用他). {in|out}[bw]_p() 等函式就是使用这个要领来发生时间延迟的 (请参考档案 asm/io.h).

              现实上, 一个使用到埠位址□围为 0-0x3ff 的 I/O 埠指令险些只要 1 微秒的时间, 以是若是你要云云做, 例如, 直接使用并列埠, 只要加上几个 inb() 函式从该 埠位址□围读入 byte 的资料即可.

              使用组合语言来延迟时间

              若是你知道执行程式所在机械的处置惩罚器型别与时钟速率, 你可以执行某些组合语言指令以便获得较短的延迟时间 (可是记着, 你在执行中的行程 (process) 随时会被暂停, 以是有时延迟的时间会比现实长). 如下面的表格所示, 内部处置惩罚器的速率决议了所要使用的时钟周期数; 如, 一个 50 MHz 的处置惩罚器 (486DX-50 或 486DX2-50), 一个时钟周期要破费 1/50000000 秒 (=200 奈秒).

              指令 i386 时钟周期数 i486 时钟周期数nop 3 1xchg %ax,%ax 3 3or %ax,%ax 2 1mov %ax,%ax 2 1add %ax,0 2 1

              (对不起, 我不知道 Pentiums 的资料, 或许与 i486 靠近吧. 我无法在 i386 的资料上找到只破费一个时钟周期的指令. 若是能够就请使用破费一个时钟周期的指令, 要否则就使用管线手艺的新式处置惩罚器也是可以缩短时间的.)

              上面的表格中指令 nop 与 xchg 应该不会有不良的後果. 指令最後可能会 改变旗帜暂存器的内容, 可是这没关系由于 gcc 会处置惩罚. 指令 nop 是个好的选择.

              想要在你的程式中使用到这些指令, 你得使用 asm("instruction"). 指令的语法就犹如上面表格的用法; 若是你想要在单一的 asm() 叙述中使用多个指令, 可以使用分号将他们离隔. 例如, asm("nop ; nop ; nop ; nop") 会执行四个 nop 指令, 在 i486 或 Pentium 处置惩罚器中会延迟四个时钟周期 (或是 i386 会延迟 12 个时钟周期).

              gcc 会将 asm() 翻译成单行组合语言程式码, 以是不会有呼叫函式的负荷.

              在 Intel x86 架构中不行能有比一个时钟周期还短的时间延迟.

              在 Pentiums 处置惩罚器上使用函式 rdtsc

              对於 Pentiums 处置惩罚器而言, 你可以使用下面的 C 语言程式码来取得自从上次重新开机 到现在经由了几多个时钟周期:

              --------------------------------------------------------------------------------

              extern __inline__ unsigned long long int rdtsc() { unsigned lon12下一页