Linux 高精確的時序(sleep, usleep,nanosleep) from:http://blog.sina.com.cn/s/blog_533ab41c0100htae.html
首先, 我会说不保证你在使用者模式 (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)
使用说明文件. 有一个特殊的核心支援硬体的即时排程; 详细的资讯请参考网页http://luz.cs.nmt.edu/~rtlinux/
休息中 (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 1
xchg %ax,%ax 3 3
or %ax,%ax 2 1
mov %ax,%ax 2 1
add %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 long long int x;
__asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
return x;
}
你可以询问参考此值以便延迟你想要的时钟周期数.
想要时间精确到一秒钟, 使用函式
time()
或许是最简单的方法. 想要时间更精确, 函式
gettimeofday()
大约可以精确到微秒 (但是如前所述会受到 CPU 排程的影响). 至於 Pentiums 处理器, 使用上面的程式码片断就可以精确到一个时钟周期.
如果你要你执行中的行程 (process) 在一段时间到了之後能够被通知 (get a signal), 你得使用函式
setitimer()
或
alarm()
. 细节请参考函式的使用说明文件.
应用程序:
#include <syswait.h>
usleep(n) //n微秒
Sleep(n)//n毫秒
sleep(n)//n秒
驱动程序:
#include <linux/delay.h>
mdelay(n) //milliseconds 其实现
#ifdef notdef
#define mdelay(n) (\
{unsigned long msec=(n); while (msec--) udelay(1000);})
#else
#define mdelay(n) (\
(__builtin_constant_p(n) && (n)<=MAX_UDELAY_MS) ? udelay((n)*1000) : \
({unsigned long msec=(n); while (msec--) udelay(1000);}))
#endif
调用 asm/delay.h的udelay,udelay应该是纳秒级的延时
Dos:
sleep(1); //停留1秒
delay(100); //停留100毫秒
Windows:
Sleep(100); //停留100毫秒
Linux:
sleep(1); //停留1秒
usleep(1000); //停留1毫秒
每一个平台不太一样, 最好自己定义一套跨平台的宏进行控制
秒还是微秒?关于延时函数sleep()
因为要写一段代码,需要用到sleep()函数,在我印象中,sleep(10)好像是休眠10微秒,结果却是休眠了10秒(在Linux下)。觉得很奇 怪,因为头儿也记得好像是微秒为单位的。所以就查了一下。
原来linux下的sleep函数原型为:
unsigned int sleep(unsigned int seconds);
而MFC中的 Sleep函数原型为:
void Sleep(DWORD dwMilliseconds);
也就是说,Linux下(使用的gcc的 库),sleep()函数是以秒为单位的,sleep(1);就是休眠1秒。而MFC下的sleep()函数是以微秒为单位的,sleep(1000); 才是休眠1秒。原来如此啊。而如果在Linux下也用微妙为单位休眠,可以使用线程休眠函数:void usleep(unsigned long usec);当然,使用的时候别忘记#include <system.h>哦。
另外值得一提的是,linux下还有个delay()函数,原型为extern void delay(unsigned int msec);它可以延时msec*4毫秒,也就是如果想延时一秒钟的话,可以这么用 delay(250);
小小一个延时函数原来还有这么多学问,任何一点代码都不可小看啊。
Linux 高精確的時序(sleep, usleep,nanosleep) from:http://blog.sina.com.cn/s/blog_533ab41c0100htae.html的更多相关文章
- linux环境变量配置,转载地址:http://blog.sina.com.cn/rss/1650981242.xml
学习总结 1.Linux的变量种类按变量的生存周期来划分,Linux变量可分为两类:1. 永久的:需要修改配置文件,变量永久生效.2. 临时的:使用export命令行声明即可,变量在关 ...
- noip 2012 国王游戏(贪心+高精)
/* 我是不会说我考试的时候想到了正解却把金币取大看成金币求和的.... 觉得只按左右手乘积排序不太对 有反例 也可能我反例放到这个题里是错的吧 按自己的理解排的序 就是各种讨论... 假设 第i个人 ...
- 【题解】洛谷P1066 [NOIP2006TG] 2^k进制数(复杂高精+组合推导)
洛谷P1066:https://www.luogu.org/problemnew/show/P1066 思路 挺难的一道题 也很复杂 满足题目要求的种数是两类组合数之和 r的最多位数m为 w/k(当w ...
- c++ 普通高精除高精
//codevs3118 高精度练习之除法 //打出了高精除高精,内心有点小激动. //还记得已开始学的时候非常难打 #include<cstdio>#include<cstring ...
- c++普通高精加
//作为一名蒟蒻,还请诸位不要吐槽. //第一次打c++高精加,内心有点小激动. //为codevs3116 高精度练习之加法 //程序太简单,就不打注释了. #include<cstdio&g ...
- BZOJ_1002_[FJOI2007]_轮状病毒_(递推+高精)
描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1002 )*&*(^&*^&*^**()*) 1002: [FJOI20 ...
- bzoj 3287: Mato的刷屏计划 高精水题 && bzoj AC150
3287: Mato的刷屏计划 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 124 Solved: 43[Submit][Status] Desc ...
- codevs 3119 高精度练习之大整数开根 (各种高精+压位)
/* codevs 3119 高精度练习之大整数开根 (各种高精+压位) 二分答案 然后高精判重 打了一个多小时..... 最后还超时了...压位就好了 测试点#1.in 结果:AC 内存使用量: 2 ...
- vijos P1375 大整数(高精不熟的一定要做!)
/* 我尼玛这题不想说啥了 亏了高精写的熟..... 加减乘除max都写了 高精二分 */ #include<iostream> #include<cstdio> #inclu ...
随机推荐
- 学习WebSocket(一):Spring WebSocket的简单使用
1.什么是websocket? WebSocket协议定义了一种web应用的新功能,它实现了服务器端和客户端的全双工通信.全双工通信即通信的双方可以同时发送和接收信息 的信息交互方式.它是继Java ...
- 关于使用struts2时子窗体页面跳转后在父窗体打开的问题以及Session过期后的页面跳转问题
问题1:传统的系统界面,iframe了三个页面,上,左,右,用户点击注销的按钮在上面得top.jsp里面,方法:<a href="../adminAction/admin_logout ...
- Leetcode 132. Palindrome Partitioning II
求次数的问题一般用DP class Solution(object): def minCut(self, s): """ :type s: str :rtype: int ...
- 【BZOJ-4173】数学 欧拉函数 + 关于余数的变换
4173: 数学 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 306 Solved: 163[Submit][Status][Discuss] D ...
- UOJ264 【NOIP2016】蚯蚓
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...
- 百度地图学习(II)-Android端的定位
哎,经历了小编的最近时间的研究,我的百度定位终于成功啦,刹那间觉得自己萌萌哒啦(- ̄▽ ̄)- 话不多说,直接进入正题: 首先,我们来看一下效果: [分析定位原理] [编码分析] 1)处理程序的清单文件 ...
- maven仓库没有的包依赖
如果有个jar包是我们自己打的,怎么放到maven中呢? 首先在项目里面新建一个lib目录,如果有lib目录则不需要新建,然后放自己的jar包进去,maven的pom.xml配置是: <depe ...
- 20个命令行工具监控Linux系统性能
作为Linux/Unix 系统管理员需要掌握一些常用的工具用于检测系统性能.在这里,dodo为大家推荐非常20个有用的并且最常用的命令行系统监视工具: 1. top -Linux系统进程监控 top ...
- 利用mybatis的分页插件实现商品列表的显示
分析思路: 当我们点击查询商品的时候,会出现商品的列表,并按上下页可以实现分页的查询的功能. 首先首先我们先找到商品查询商品的按钮在jsp的那个页面,即首页index.jsp 这里有个url即显示商品 ...
- MYSQL 常用函数(数学、字符串、日期时间、系统信息、加密)
一.数学函数 数学函数主要用于处理数字,包括整型.浮点数等. ABS(x) 返回x的绝对值 SELECT ABS(-1) -- 返回1 CEIL(x),CEILING(x) 返回大于或等于x的最小整数 ...
转载▼