linux 内核长延时方法

   忙等待

如果你想延时执行多个时钟嘀哒, 允许在值中某些疏忽, 最容易的( 尽管不推荐 ) 的实
现是一个监视 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 秒在展示的例子中并且随时间上升. 这些值显示了进程在它的延时
当中被中断, 调度其他的进程. 系统调用之间的间隙不是唯一的这个进程的调度选项, 因
此没有特别的延时在那里可以看到.

 让出处理器

如我们已见到的, 忙等待强加了一个重负载给系统总体; 我们乐意找出一个更好的技术.
想到的第一个改变是明确地释放 CPU 当我们对其不感兴趣时. 这是通过调用调度函数而
实现地, 在 <linux/sched.h> 中声明:
while (time_before(jiffies, j1)) {
schedule();
}
这个循环可以通过读取 /proc/jitsched 如同我们上面读 /proc/jitbusy 一样来测试.
但是, 还是不够优化. 当前进程除了释放 CPU 不作任何事情, 但是它保留在运行队列中.
如果它是唯一的可运行进程, 实际上它运行( 它调用调度器来选择同一个进程, 进程又调
用调度器, 这样下去). 换句话说, 机器的负载( 在运行的进程的平均数 ) 最少是 1, 并
且空闲任务 ( 进程号 0, 也称为对换进程, 由于历史原因) 从不运行. 尽管这个问题可
能看来无关, 在计算机是空闲时运行空闲任务减轻了处理器工作负载, 降低它的温度以及
提高它的生命期, 同时电池的使用时间如果这个计算机是你的膝上机. 更多的, 因为进程
实际上在延时中执行, 它所耗费的时间都可以统计.
/proc/jitsched 的行为实际上类似于运行 /proc/jitbusy 在一个抢占的内核下. 这是一
个例子运行, 在一个无负载的系统:
phon% dd bs=20 count=5 < /proc/jitsched
1760205 1761207
1761209 1762211
1762212 1763212
1763213 1764213
1764214 1765217
有趣的是要注意每次 read 有时结束于等待比要求的多几个时钟嘀哒. 这个问题随着系统
变忙会变得越来越坏, 并且驱动可能结束于等待长于期望的时间. 一旦一个进程使用调度
来释放处理器, 无法保证进程将拿回处理器在任何时间之后. 因此, 以这种方式调用调度
器对于驱动的需求不是一个安全的解决方法, 另外对计算机系统整体是不好的. 如果你在
运行 load50 时测试 jitsched, 你可以见到关联到每一行的延时被扩充了几秒, 因为当
定时超时的时候其他进程在使用 CPU .

超时

到目前为止所展示的次优化的延时循环通过查看 jiffy 计数器而不告诉任何人来工作.
但是最好的实现一个延时的方法, 如你可能猜想的, 常常是请求内核为你做. 有 2 种方
法来建立一个基于 jiffy 的超时, 依赖于是否你的驱动在等待其他的事件.
如果你的驱动使用一个等待队列来等待某些其他事件, 但是你也想确保它在一个确定时间
段内运行, 可以使用 wait_event_timeout 或者 wait_event_interruptible_timeout:
#include <linux/wait.h>
long wait_event_timeout(wait_queue_head_t q, condition, long timeout);
long wait_event_interruptible_timeout(wait_queue_head_t q, condition, long
timeout);
这些函数在给定队列上睡眠, 但是它们在超时(以 jiffies 表示)到后返回. 因此, 它们
实现一个限定的睡眠不会一直睡下去. 注意超时值表示要等待的 jiffies 数, 不是一个
绝对时间值. 这个值由一个有符号的数表示, 因为它有时是一个相减运算的结果, 尽管这
些函数如果提供的超时值是负值通过一个 printk 语句抱怨. 如果超时到, 这些函数返回
0; 如果这个进程被其他事件唤醒, 它返回以 jiffies 表示的剩余超时值. 返回值从不会
是负值, 甚至如果延时由于系统负载而比期望的值大.
/proc/jitqueue 文件展示了一个基于 wait_event_interruptible_timeout 的延时, 结
果这个模块没有事件来等待, 并且使用 0 作为一个条件:
wait_queue_head_t wait;
init_waitqueue_head (&wait);
wait_event_interruptible_timeout(wait, 0, delay);
当读取 /proc/jitqueue 时, 观察到的行为近乎优化的, 即便在负载下:
phon% dd bs=20 count=5 < /proc/jitqueue
2027024 2028024
2028025 2029025
2029026 2030026
2030027 2031027
2031028 2032028
因为读进程当等待超时( 上面是 dd )不在运行队列中, 你看不到表现方面的差别, 无论
代码是否运行在一个抢占内核中.
wait_event_timeout 和 wait_event_interruptible_timeout 被设计为有硬件驱动存在,
这里可以用任何一种方法来恢复执行: 或者有人调用 wake_up 在等待队列上, 或者超时
到. 这不适用于 jitqueue, 因为没人在等待队列上调用 wake_up ( 毕竟, 没有其他代码
知道它 ), 因此这个进程当超时到时一直唤醒. 为适应这个特别的情况, 这里你想延后执
行不等待特定事件, 内核提供了 schedule_timeout 函数, 因此你可以避免声明和使用一
个多余的等待队列头:

#include <linux/sched.h>
signed long schedule_timeout(signed long timeout);
这里, timeout 是要延时的 jiffies 数. 返回值是 0 除非这个函数在给定的 timeout
流失前返回(响应一个信号). schedule_timeout 请求调用者首先设置当前的进程状态,
因此一个典型调用看来如此:
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout (delay);
前面的行( 来自 /proc/jitschedto ) 导致进程睡眠直到经过给定的时间. 因为
wait_event_interruptible_timeout 在内部依赖 schedule_timeout, 我们不会费劲显示
jitschedto 返回的数, 因为它们和 jitqueue 的相同. 再一次, 不值得有一个额外的时
间间隔在超时到和你的进程实际被调度来执行之间.
在刚刚展示的例子中, 第一行调用 set_current_state 来设定一些东西以便调度器不会
再次运行当前进程, 直到超时将它置回 TASK_RUNNING 状态. 为获得一个不可中断的延时,
使用 TASK_UNINTERRUPTIBLE 代替. 如果你忘记改变当前进程的状态, 调用
schedule_time 如同调用 shcedule( 即, jitsched 的行为), 建立一个不用的定时器.
如果你想使用这 4 个 jit 文件在不同的系统情况下或者不同的内核, 或者尝试其他的方
式来延后执行, 你可能想配置延时量当加载模块时通过设定延时模块参数.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/431850.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

郑州it java_郑州Java网站开发

详细信息&#xff1a;阶段&#xff1a;Java语言基础&#xff1a;Java开发环境配置、编程基础、算法基础、常用数据结构、企业编程规范。Java面向对象&#xff1a;理解java面向对象的思想&#xff0c;掌握面向对象特性&#xff1a;封装、继承、多态等&#xff0c;面向对象程序设…

UESTC_秋实大哥下棋 2015 UESTC Training for Data StructuresProblem I

I - 秋实大哥下棋 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Submit Status胜负胸中料已明&#xff0c;又从堂上出奇兵。秋实大哥是一个下棋好手&#xff0c;独孤求败的他觉得下棋已经无法满足他了&#xff0c;他开始研究一种新的…

java数据类型及表示范围_Java数据类型及对应取值范围

在Java中&#xff0c;数据类型分为两大种&#xff1a;基本数据类型(值类型)和包装类型(引用数据类型)。基本数据类型不是对象&#xff0c;不能调用toString()、hashCode()、getClass()、equals()等方法。8种基本数据类型-----8种包装类型整型&#xff1a;byte  Byte     …

java开发cgi_編寫CGI小結(Java)

轉載請注明出處&#xff1a;http://blog.csdn.net/hungryhuang/article/details/6601684。由於Carl要用到我的程序&#xff0c;我們便合作工作。但是他寫的程序是Python的&#xff0c;我寫的程序是Java的&#xff0c;必須得找一種方式進行通信。盡管有Jython這些東西&#xff0…

腾讯后台开发面试总结,原创,吐血推荐!!

前段时间专心面过腾讯&#xff0c;经过了N轮的技术面&#xff0c;结果还是挂了&#xff0c;但没挂在技术面&#xff0c;比较欣慰&#xff0c;回来之后写一点总结&#xff0c;以供有梦想进入腾讯做后台服务器开发的同学参考&#xff0c;本文章为胡成精心总结&#xff0c;胡成原创…

java 6大原则_java 6大设计原则 一:观察者模式

解耦常用的模式OrderService.javaServicepublic class OrderService{AutowiredApplicationContext applicationContext ;public void saveOrder(){//1.创建订单System.out.println(“1.创建订单”)&#xff1b;OrderEvent event new OrderEvent("参数")application…

jbb是什么梗_子水是什么意思,子水命理

子水是十二地支之一&#xff0c;那么命中有子水的代表的是什么呢&#xff1f;适合什么方位呢&#xff1f;有什么喜忌吗&#xff1f;怎么分析你呢?现在金宝贝起名网为你介绍子水是什么意思,子水命理的相关文章。子水是什么意思,子水命理八字地支&#xff1a;子水是什么意思1、对…

java语言实现一个长度为n_Java语言实现求解一元n次多项式的方法示例[Java代码]...

本文主要向大家介绍了Java语言实现求解一元n次多项式的方法示例&#xff0c;通过具体的内容向大家展示&#xff0c;希望对大家学习JAVA语言有所帮助。项目需要做趋势预测&#xff0c;采用线性拟合、2阶曲线拟合和指数拟合的算法&#xff0c;各种线性拟合算法写成矩阵大概是这么…

java rmi 是否 必要_Java学习之路-RMI学习

Java远程方法调用&#xff0c;即Java RMI(Java Remote Method Invocation)是Java编程语言里&#xff0c;一种用于实现远程过程调用的应用程序编程接口。它使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性使Java编程人员能够在网络环境中分布操作。RMI全部的…

c++将文本中的字符串一次读入到内存

这段代码是将文本文件中的全部字符读入到内存中&#xff0c;这样的速度是很快的 char buf[1024*800];int MAXS 10000000;freopen("d:\\4.txt", "rb", stdin);int len fread(buf, 1, 100000, stdin);buf[len] \0;cout << buf[10]; 转载于:https://…

JAVA写同步栈_tomcat实现的同步队列和同步栈

tomcat实现的同步队列&#xff0c;同步栈用于数据量比较固定且基本很少删除的场景&#xff0c;尽可能减少内存消耗。同步队列/** Licensed to the Apache Software Foundation (ASF) under one or more* contributor license agreements. See the NOTICE file distributed with…

IOS高级编程之二:IOS的数据存储与IO

一、应用程序沙盒 IOS应用程序职能在系统为该应用所分配的文件区域下读写文件&#xff0c;这个文件区域就是应用程序沙盒。所有的非代码文件如&#xff1a;图片、声音、映象等等都存放在此。 在mac中command&#xff0b;shift&#xff0b;G命令&#xff0c;然后输入users/用户名…

安卓投屏大师_苹果,安卓手机如何免费投屏?只要悄悄按下这里,便能轻松实现...

现在很多手机都有自带投屏功能&#xff0c;这样一来我们便可以将所看的视频&#xff0c;所玩的游戏投屏到电脑或电视上了&#xff0c;当然也需要这些设备支持投屏才行。一、无线投屏1、苹果手机苹果手机的投屏功能在哪里呢&#xff1f;只要打开苹果手机从下往上滑动&#xff0c…

java 反射解析xml_java反射获取xml元素

类名:class Person {public void run(String who){System.out.println("Person::run()" who);}public void jump(String who){System.out.println("Person::jump()" who);}public void run(){System.out.println("Person::run()");}public voi…

怎样的中奖算法能让人信服

话说写一个抽奖程序还不容易&#xff0c;不就是生成一个随机数吗&#xff0c;哪需什么算法之类的。 从技术上说&#xff0c;这确实不难。事实上&#xff0c;你怎么写都可以&#xff0c;因为程序只运行在特定的设备上&#xff0c;外人根本无法了解其中的细节。 那么问题就来了&a…

b站电脑客户端_如何将B站的flv格式的视频转换成mp4格式

经常看到B站有精彩的视频片段&#xff0c;于是想把这些视频下载保存到电脑&#xff0c;但是发现没有下载按钮&#xff0c;是不是很悲催。有些时候想从优酷、土豆网这些视频网站下载视频&#xff0c;结果却提示要先下载视频客户端才能继续下载视频&#xff0c;运气差的话&#x…

linux Packet socket (1)简单介绍

本文主要来自于linux自带的man packet手冊&#xff1a; http://man7.org/linux/man-pages/man7/packet.7.html 平时常常使用的INET套接字提供的是7层的抓包能力&#xff0c;抓上来的data直接就是tcp或者udp的payload&#xff0c;无需关心L3和L4的头部信息。 Packet套接字提供的…

asp.net 设置 excel alignment_教你如何用Python轻轻松松操作Excel、Word、CSV,一文就够了,赶紧码住!!!...

作者&#xff1a;奈何缘浅wyjhttps://juejin.im/post/6868073137263607821Python 操作 Excel常用工具数据处理是 Python 的一大应用场景&#xff0c;而 Excel 又是当前最流行的数据处理软件。因此用 Python 进行数据处理时&#xff0c;很容易会和 Excel 打起交道。得益于前人的…

java 页面输出一个页面_java学习之:一个完整页面输出信息的过程(以输出Doctor表中信息为例)...

最近在练习java程序&#xff0c;总结一下从数据库查询信息并输出到jsp页面的过程。主要数据处理在src.cn.javatest包下面项目预览1&#xff0c;配置项目根目录src目录下的druid.properties数据库信息(相当于一个数据库配置文件)里面的信息可以在下载druid中获得&#xff0c;只需…

[xsd学习]xsd介绍

一直以来项目中对xml格式的判断使用的都是dtd格式&#xff0c;直到最近才发现&#xff0c;不知何时都已经转为xsd来进行判断和校验&#xff0c;于是今天专门找资料看下&#xff0c;不得不说&#xff0c;对于这类资料的入门&#xff0c;w3cschool真是个不错的资料库&#xff0c;…