设备驱动常常需要延后一段时间执行一个特定片段的代码, 常常允许硬件完成某个任务. 在这一节我们涉及许多不同的技术来获得延后. 每种情况的环境决定了使用哪种技术最好; 我们全都仔细检查它们, 并且指出每一个的长处和缺点.

一件要考虑的重要的事情是你需要的延时如何与时钟嘀哒比较, 考虑到 HZ 的跨各种平台 的范围. 那种可靠地比时钟嘀哒长并且不会受损于它的粗粒度的延时, 可以利用系统时钟. 每个短延时典型地必须使用软件循环来实现. 在这 2 种情况中存在一个灰色地带. 在本 章, 我们使用短语" long " 延时来指一个多 jiffy 延时, 在一些平台上它可以如同几个 毫秒一样少, 但是在 CPU 和内核看来仍然是长的.

下面的几节讨论不同的延时, 通过采用一些长路径, 从各种直觉上不适合的方法到正确的 方法. 我们选择这个途径因为它允许对内核相关定时方面的更深入的讨论. 如果你急于找 出正确的代码, 只要快速浏览本节.

长延时

 

偶尔地, 一个驱动需要延后执行相对长时间 -- 多于一个时钟嘀哒. 有几个方法实现这类 延时; 我们从最简单的技术开始, 接着进入到高级些的技术.

忙等待

 

如果你想延时执行多个时钟嘀哒, 允许在值中某些疏忽, 最容易的( 尽管不推荐 ) 的实 现是一个监视 jiffy 计数器的循环. 这种忙等待实现常常看来象下面的代码, 这里 j1 是 jiffies 的在延时超时的值:

while (time_before(jiffies, j1)) cpu_relax();

对 cpu_relex 的调用使用了一个特定于体系的方式来说, 你此时没有在用处理器做事情. 在许多系统中它根本不做任何事; 在对称多线程(" 超线程" ) 系统中, 可能让出核心给 其他线程. 在如何情况下, 无论何时有可能, 这个方法应当明确地避免. 我们展示它是因 为偶尔你可能想运行这个代码来更好理解其他代码的内幕.

我们来看一下这个代码如何工作. 这个循环被保证能工作因为 jiffies 被内核头文件声 明做易失性的, 并且因此, 在任何时候 C 代码寻址它时都从内存中获取. 尽管技术上正 确( 它如同设计的一样工作 ), 这种忙等待严重地降低了系统性能. 如果你不配置你的内 核为抢占操作, 这个循环在延时期间完全锁住了处理器; 调度器永远不会抢占一个在内核 中运行的进程, 并且计算机看起来完全死掉直到时间 j1 到时. 这个问题如果你运行一个 可抢占的内核时会改善一点, 因为, 除非这个代码正持有一个锁, 处理器的一些时间可以 被其他用途获得. 但是, 忙等待在可抢占系统中仍然是昂贵的.

更坏的是, 当你进入循环时如果中断碰巧被禁止, jiffies 将不会被更新, 并且 while 条件永远保持真. 运行一个抢占的内核也不会有帮助, 并且你将被迫去击打大红按钮.

这个延时代码的实现可拿到, 如同下列的, 在 jit 模块中. 模块创建的这些 /proc/jit* 文件每次你读取一行文本就延时一整秒, 并且这些行保证是每个 20 字节. 如果你想测试 忙等待代码, 你可以读取 /proc/jitbusy, 每当它返回一行它忙-循环一秒.

为确保读, 最多, 一行( 或者几行 ) 一次从 /proc/jitbusy. 简化的注册 /proc 文件的 内核机制反复调用 read 方法来填充用户请求的数据缓存. 因此, 一个命令, 例如 cat

/proc/jitbusy, 如果它一次读取 4KB, 会冻住计算机 205 秒.

推荐的读 /proc/jitbusy 的命令是 dd bs=200 < /proc/jitbusy, 可选地同时指定块数 目. 文件返回的每 20-字节 的行表示 jiffy 计数器已有的值, 在延时之前和延时之后. 这是一个例子运行在一个其他方面无负担的计算机上:

phon% dd

bs=20 count=5 < /proc/jitbusy

1686518

1687518

1687519

1688519

1688520

1689520

1689520

1690520

1690521

1691521

看来都挺好: 延时精确地是 1 秒 ( 1000 jiffies ), 并且下一个 read 系统调用在上一 个结束后立刻开始. 但是让我们看看在一个有大量 CPU-密集型进程在运行(并且是非抢占 内核)的系统上会发生什么:

phon% dd

bs=20 count=5 < /proc/jitbusy

1911226

1912226

1913323

1914323

1919529

1920529

1925632

1926632

1931835

1932835

这里, 每个 read 系统调用精确地延时 1 秒, 但是内核耗费多过 5 秒在调度 dd 进程以 便它可以发出下一个系统调用之前. 在一个多任务系统就期望是这样; CPU 时间在所有运 行的进程间共享, 并且一个 CPU-密集型 进程有它的动态减少的优先级. ( 调度策略的讨 论在本书范围之外).

上面所示的在负载下的测试已经在运行 load50 例子程序中进行了. 这个程序派生出许多 什么都不做的进程, 但是以一种 CPU-密集的方式来做. 这个程序是伴随本书的例子文件 的一部分, 并且缺省是派生 50 个进程, 尽管这个数字可以在命令行指定. 在本章, 以及 在本书其他部分, 使用一个有负载的系统的测试已经用 load50 在一个其他方面空闲的计 算机上运行来进行了.

如果你在运行一个可抢占内核时重复这个命令, 你会发现没有显著差别在一个其他方面空 闲的 CPU 上以及下面的在负载下的行为:

phon% dd bs=20 count=5 < /proc/jitbusy 14940680 14942777

14942778 14945430

14945431

14948491

14948492

14951960

14951961

14955840

这里, 没有显著的延时在一个系统调用的末尾和下一个的开始之间, 但是单独的延时远远 比 1 秒长: 直到 3.8 秒在展示的例子中并且随时间上升. 这些值显示了进程在它的延时 当中被中断, 调度其他的进程. 系统调用之间的间隙不是唯一的这个进程的调度选项, 因 此没有特别的延时在那里可以看到.

linux 延后执行的更多相关文章

  1. innerHTML 延后执行?

    时常会觉得 innerHTML 可能有延后执行的情况,比如下面代码: document.body.innerHTML = 'something'; alert('something else'); 明 ...

  2. golang defer 延后执行什么

    对于golang的defer,我们已经知道,defer定义的语句可以延后到函数返回时执行. 经常用在文件的关闭,锁的释放等场景中.而且defer定义的语句即使遇到panic也会执行.这样,可以执行必要 ...

  3. paramiko 登录linux主机后执行tail后返回数据不完整解决方法。

    def get_sql_log(host,port,user,password,key_words,out_put_filename): commond='cd crm-app/;./tailall. ...

  4. Linux查找后执行命令

    find . -name '*.jsp' -type f -print -exec rm -rf {} \; 在当前目录下找到jsp文件并删除.

  5. 延宕执行,妙用无穷,Go lang1.18入门精炼教程,由白丁入鸿儒,Golang中defer关键字延迟调用机制使用EP17

    先行定义,延后执行.不得不佩服Go lang设计者天才的设计,事实上,defer关键字就相当于Python中的try{ ...}except{ ...}finally{...}结构设计中的finall ...

  6. linux下Tomcat 安装后执行startup.sh,出现– Cannot find …bin/catalina.sh

    linux下Tomcat 安装后执行startup.sh,出现– Cannot find …bin/catalina.sh 是因为权限不够,执行以下命令就可以: chmod +x startup.sh ...

  7. Linux下定时执行脚本(转自Decode360)

    文章来自:http://www.blogjava.net/decode360/archive/2009/09/18/287743.html Decode360's Blog  老师(业精于勤而荒于嬉 ...

  8. linux下定时执行任务方法【转】

     之前就转过一篇关于定时任务的文章,前俩天用,还的翻出来看!!!再转一次,备用,,需要的时候不用麻烦找! ----------------------------------------------- ...

  9. 泛函编程(11)-延后计算-lazy evaluation

    延后计算(lazy evaluation)是指将一个表达式的值计算向后拖延直到这个表达式真正被使用的时候.在讨论lazy-evaluation之前,先对泛函编程中比较特别的一个语言属性”计算时机“(s ...

随机推荐

  1. 【JZOJ4934】【NOIP2017GDKOI模拟1.12】a

    helpless fucking 结论:如果一个数可以被对于a序列中每个数的最大公约数整除,那么它就是好的. Bitch Man 感性证明: 贪心地想,对于a序列中的任意两个数,它们的最大公约数可由这 ...

  2. BigDecimal创建初始化值类型对比

    当初始化String类型和double类型,入参值相同,对比输出值 BigDecimal bigDecimalStr = new BigDecimal("0.1"); BigDec ...

  3. prepareStatement设置参数,mysql数据出现中文‘?’的情景与解决方式

    在prepareStatement中传入中文的参数,mysql数据库中出现“?”号 try { Class.forName("com.mysql.jdbc.Driver"); co ...

  4. 【Leetcode链表】旋转链表(61)

    题目 给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: 1->2->3->4->5->NULL, k = 2 输出: ...

  5. Python学习之路7☞装饰器

    一:命名空间与作用域 1.1命名空间 局部命名空间: def foo(): x=1 def func(): pass 全局命名空间: import time class ClassName:pass ...

  6. SDUT-2120_数据结构实验之链表五:单链表的拆分

    数据结构实验之链表五:单链表的拆分 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 输入N个整数顺序建立一个单链表,将该 ...

  7. jQuery学习笔记之可见性过滤选择器

    可见性过滤选择器是根据元素的可见和不可见状态来选择相应的元素. 显示隐藏的例子: <!DOCTYPE html> <html> <head> <script ...

  8. golang micro client 报错500 {"id":"go.micro.client","code":408,"detail":"call timeout: context deadline exceeded","status":"Request Timeout"}

    go micro web端连接services时,第一次访问提示500(broken pipe),排查发现客户端请求services时返回 {"id":"go.micro ...

  9. 使用epoll实现简单的服务器

    1. 头文件 #ifndef __TCP_SERVER_H__ #define __TCP_SERVER_H__ #include <unistd.h> #include <stdi ...

  10. hdu 1077 (圆交)

    Problem - 1077 我们可以知道,当这个单位圆可以覆盖到最多的点的时候,必定最少有两个点位于这个圆的圆周上,于是就有网上众多的O(N^3)的枚举两个在圆上的点的暴搜做法. 然而这题是可以用圆 ...