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

一件要考虑的重要的事情是你需要的延时如何与时钟嘀哒比较, 考虑到 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. Seata 0.7.0 正式发布

    Seata 是 阿里巴巴 开源的 分布式事务中间件,以 高效 并且对业务 0 侵入 的方式,解决 微服务 场景下面临的分布式事务问题.Seata 0.7.0 已正式发布,本次共合并59pr,主要包括: ...

  2. 笔记: CC2540 和 CC2541 的区别

    CC2540 和 CC2541 的区别 CC2540 和 CC2541 是 BLE 低功耗蓝牙芯片,使用的是 51 内核. CC2540 有 USB 接口 CC2541 无. 价格上最早是 CC254 ...

  3. thinkphp5.0验证码使用

    如果没有安装验证码类,可在composer.json 文件的require里面添加 "topthink/think-captcha":"1.*",然后compo ...

  4. [CS]C#操作word 2016-04-17 18:30 1506人阅读 评论(35) 收藏

    最近在做的项目已经改了好几版,最近这一版用到了word,当然不是直接使用word,而是使用第三方的ActiveX控件:dsoframer.ocx,此控件的使用和其他控件的使用流程没有任何区别,接下来介 ...

  5. SprinfJdbcTemplate+SpringMVC 代码生成器实现的Entity,Dao,Service,Controller,JSP神器(含代码附件)

    代码生成器实现的Entity,Dao,Service,Controller,JSP神器(含代码附件) 原文地址: http://jilongliang.iteye.com/blog/2262070 p ...

  6. 开发者说:如何参与定义一款 IDE 插件

    摘要: If not now,when? If not you,who?共同定义 Cloud Toolkit 的未来! 自从产品经理银时小伙和他的开发小哥们在去年12月发布 Cloud Toolkit ...

  7. 网站的域名带www的和不带www的有什么区别呀

    国内用户习惯用www,不过默认的不带www的域名要好过带www的,带Www的是二级域名,不带的是顶级域名,默认的在搜索引擎中得权重会比较高 区别就在于一个带www一个不带www 其他都一样.www的域 ...

  8. 6、mysql的安装

    1.安装mysql-Server,并输入root密码 sudo apt-get install mysql-server 2.安装mysql客户端 sudo apt-get install mysql ...

  9. Jquery常用方法汇总(转)

    https://blog.csdn.net/lucky___star/article/details/87883888

  10. vue3——vue数据循环渲染

    博客地址 :https://www.cnblogs.com/sandraryan/ vue循环渲染 <!DOCTYPE html> <html lang="en" ...