当前位置: 首页 > news >正文

udelay、mdelay、ndelay、msleep使用比较说明

 时间单位:  
  毫秒(ms)、微秒 (μs)、纳秒(ns)、皮秒(ps)、飞秒(fs)、阿秒、渺秒  
  1 s = 10^3 ms = 10^6 us = 10^9 ns = 10^12 ps = 10^15 fs=10^18阿秒=10^21渺秒=10^43普朗克常数

在Linux Driver开发中,经常要用到延迟函数:msleep,mdelay/udelay.

虽然msleep和mdelay都有延迟的作用,但他们是有区别的.

mdeday还忙等待函数(相当于for循环)在延迟过程中无法运行其他任务.这个延迟的时间是准确的.是需要等待多少时间就会真正等待多少时间.而msleep是休眠函数,它不涉及忙等待.你如果是msleep(10),那实际上延迟的时间,大部分时候是要多于10ms的,是个不定的时间值.

他们的差异,平时我也讲的出来,可是真正用起来的时候,就忘记了.曾在两个driver的i2c的code中,需要用到delay函数,而我用了msleep函数,一直I2C速度超慢.而我又不知道哪里出了问题,我潜意识中,认为我只delay了1ms,可是,实际上是十几毫秒.

 

这几个函数都是内核的延时函数:

1.

udelay(); mdelay(); ndelay();实现的原理本质上都是忙等待,ndelay和mdelay都是通过udelay衍生出来的,我们使用这些函数的实现往往会碰到编译器的警告implicit declaration of function'udelay',这往往是由于头文件的使用不当造成的。在include/asm-???/delay.h中定义了udelay(),而在include/linux/delay.h中定义了mdelay和ndelay.(这点弄错了吧,应该是ndelay最小吧)

 

udelay一般适用于一个比较小的delay,如果你填的数大于2000,系统会认为你这个是一个错误的delay函数,因此如果需要2ms以上的delay需要使用mdelay函数。

 

2.由于这些delay函数本质上都是忙等待,对于长时间的忙等待意味这无谓的耗费着cpu的资源,因此对于毫秒级的延时,内核提供了msleep,ssleep等函数,这些函数将使得调用它的进程睡眠参数指定的时间

 

应用层:
   #include <unistd.h>
   1、unsigned int sleep(unsigned int seconds); 秒级
   2、int usleep(useconds_t usec);              微秒级:1/10^-6
   #define _POSIX_C_SOURCE 199309
   #include <time.h>
   3、int nanosleep(const struct timespec *req, struct timespec *rem);
       struct timespec {
                  time_t tv_sec;        /* seconds */
                  long   tv_nsec;       /* nanoseconds */
              };
       // The value of the nanoseconds field must be in the range 0 to 999999999.
 
 内核层:
   include <linux/delay.h>
   1、void ndelay(unsigned long nsecs);         纳秒级:1/10^-10
   2、void udelay(unsigned long usecs);         微秒级: 1/10^-6
   3、void mdelay(unsigned long msecs);         毫秒级:1/10^-3

 

sleep_on(), interruptible_sleep_on(); 
sleep_on_timeout(), interruptible_sleep_on_timeout(); 
根据你的情况选用这些函数,注意: sleep操作在kernel必须小心、小心。。。 
udelay()等函数是cpu忙等,没有传统意义上的sleep。这些函数相当于我们平时的阻塞读、写之类的语义,主要用于等外设完成某些操作

 

------

nanosleep:

 struct timespec
              {
                      time_t  tv_sec;         /* seconds */
                      long    tv_nsec;        /* nanoseconds */
              };

这个函数功能是暂停某个进程直到你规定的时间后恢复,参数req就是你要暂停的时间,其中req->tv_sec是以秒为单位,而tv_nsec以毫微秒为单位(10的-9次方秒)。由于调用nanosleep是是进程进入TASK_INTERRUPTIBLE,这种状态是会相应信号而进入TASK_RUNNING状态的,这就意味着有可能会没有等到你规定的时间就因为其它信号而唤醒,此时函数返回-1,切还剩余的时间会被记录在rem中。

 

看到这里刚刚看到他的实现是:将其状态设置成TASK_INTERRUPTIBLE,脱离就绪队列,然后进行一次进程调度再由内核在规定的时间后发送信号来唤醒这个进程。

 

在我刚开始学习编程时候,那时候我也曾试图使上下2条指令相隔一定时间来运行,那时我的做法是在这2条指令之间加上了一个400次的循环。这也算一种实现方式,我管它叫作延迟,但没有利用进程休眠来实现的好。但有一种特殊情况,使用休眠就无法实现了。

 

我们知道这里肯定脱离不了时钟中断,没有时钟中断的计时我们是无法实现这一功能的。那么假设时钟种中断是10毫秒一次(这种CPU还是有的),那么我们可以看到在函数调用的时候我们可以以毫微秒来暂停,如果我tv_sec = 0, tv_nsec = 2,那么时钟中断一定是在10微秒后来唤醒这个进程的,如果非实时性任务差个8微秒估计没什么大不了,不幸的是LINUX支持实时性任务SCHED_FIFO和SCHED_RR.(我们以前谈到过)。

 

这时8微秒的差距就是不能容忍了,这是就不能靠休眠和时钟中断来实现了,这是linux采用就是延迟办法,执行一个循环来达到暂停的目的。

 

这2种实现的差别就是休眠实现的话,进程会进入休眠状态,而延迟实现的话,CPU是在执行循环不会进入休眠态。所以可以说虽然名为nanosleep,但它不一定会使进程进入sleep状态,当然不进入sleep 态的条件太苛刻(没多少人会写实时任务,且还是暂停要小于CPU时钟频率,加上现在CPU的频率是如此之高,这种情况一般发生在要求外设中断不小于某个特定值,而且应该是采用比较老的CPU或者嵌入式中)。

唤醒问题:

msleep:睡眠之后不可唤醒;

msleep_interuptible:睡眠之后可唤醒;

ssleep:s延时,睡眠时候不可唤醒;

 

转载于:https://www.cnblogs.com/Ph-one/p/4678361.html

相关文章:

  • A8下超级终端调试问题
  • Linux多线程编程(不限Linux)转
  • Linux 线程优先级
  • 男儿当自强
  • JNI编程(一) —— 编写一个最简单的JNI程序
  • JNI编程(二) —— 让C++和Java相互调用(1)
  • JNI编程(二) —— 让C++和Java相互调用(2)
  • char*,const char*和string的相互转换
  • 请问什么是UTF字符串?
  • jni数据问题
  • sprintf
  • 锦上
  • eMMC(KLM8G2FE3B)
  • jni调试3(线程调试env变量问题)
  • 在JNI中新开线程遇到问题
  • 2019.2.20 c++ 知识梳理
  • canvas 高仿 Apple Watch 表盘
  • Docker入门(二) - Dockerfile
  • ESLint简单操作
  • JavaSE小实践1:Java爬取斗图网站的所有表情包
  • js中的正则表达式入门
  • OSS Web直传 (文件图片)
  • React as a UI Runtime(五、列表)
  • XML已死 ?
  • 给初学者:JavaScript 中数组操作注意点
  • 函数式编程与面向对象编程[4]:Scala的类型关联Type Alias
  • 目录与文件属性:编写ls
  • 使用阿里云发布分布式网站,开发时候应该注意什么?
  • 算法-插入排序
  • 我是如何设计 Upload 上传组件的
  • 鱼骨图 - 如何绘制?
  • 与 ConTeXt MkIV 官方文档的接驳
  • 自制字幕遮挡器
  • 容器镜像
  • ​ssh免密码登录设置及问题总结
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • #stm32驱动外设模块总结w5500模块
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • (12)目标检测_SSD基于pytorch搭建代码
  • (70min)字节暑假实习二面(已挂)
  • (Pytorch框架)神经网络输出维度调试,做出我们自己的网络来!!(详细教程~)
  • (三十五)大数据实战——Superset可视化平台搭建
  • (五)MySQL的备份及恢复
  • (译)计算距离、方位和更多经纬度之间的点
  • (转)Oracle存储过程编写经验和优化措施
  • (转)创业家杂志:UCWEB天使第一步
  • (转载)OpenStack Hacker养成指南
  • (转载)PyTorch代码规范最佳实践和样式指南
  • (轉)JSON.stringify 语法实例讲解
  • .cfg\.dat\.mak(持续补充)
  • .NET : 在VS2008中计算代码度量值
  • .NET 5种线程安全集合
  • .NET Core IdentityServer4实战-开篇介绍与规划
  • .NET 药厂业务系统 CPU爆高分析