全部博文(10)
分类: LINUX
2014-07-08 09:20:54
定时与延时____一点总结
2014/6/11
1. 长延时-忙等-Jiffies
A:
Jiffies实际上是一种粗粒度的延时,适合做毫秒级以上的延时,因为HZ一般定义为100、200、1000,这样jiffies的粒度就分别是0.1ms、0.2ms、1ms。它有几种延时模型:
while(delay < jiffies);//忙等
B:
while(delay < jiffies)
schedule(); //让出处理器
while(time_before(jiffies, delay))
schedule(); //让出处理器睡眠,更优雅的方式,线程依然是TASK_RUNNING状态。若TASK_RUNNING队列中无其他线程,这个线程又会立即被调度执行,几乎相当于忙等。
C:
while(time_before(jiffies, delay)){
set_current_state(TASK_UNINTERRUPTIBLE);
//线程被挂到TASK_UNINTERRUPTIBLE等待队列,在TASK_RUNNING里的线程执行完后或者内核的调度机制会使得这个线程在稍后的一定时间再度投入TASK_RUNNING队列运行,也就是这样会比不使用set_current_state(TASK_UNINTERRUPTIBLE)睡眠更久。
schedule();
}
从等待的精度来说,应该是A>B>C。当然了,如果用了jiffies做忙等,说明代码对延时的精度也没有那么高的要求,精度不应该是在A、B、C之间做选择的决定因素,决定因素应该是要不要忙等或睡眠。
2. 短延时-忙等-delay-sleep系列
#include
void ndelay(unsigned long nsecs);
void udelay(unsigned long usecs);
void mdelay(unsigned long msecs);
udelay(150); //延时150微秒
jiffies延时粒度是毫秒级别以上,而这几个函数的粒度达到惊人的n秒级别。特别注意的是,这几个函数都是忙等,不会使得线程换出CPU。至于为什么这几个函数可以做到这么高的精度,因为这几个函数的实现上借助了高精度定时器以及循环指令,也就是依赖于硬件,所以它们的延时的准确度会很高。看了代码,好像是就是用到了循环执行N条指令,来达到延时。
3. 睡眠等待
set_current_state(TASK_INTERRUPTIBLE);
/*小睡一会,s秒后唤醒*/
schedule_timeout(s*HZ);
这样,可以让线程睡眠指定的时间,而不会白白占据CPU
wait_queue_head_t wait;
init_qaitqueue_head(&wait);
wait_event_interruptible_timeout(wait, 0, s*HZ); //延时s秒
等待队列,实际上也是基于schedule()来实现的,只不过功能上比schedule()更强大。等待队列加入了等待条件,这也是和schedule()的区别所在。
所以,如果只是单纯的让内核线程睡眠等待一会,或者睡眠等待指定的时间,那么就用schedule()或者schedule_timeout();如果等待睡眠时需要满足特定的条件才可以被唤醒,那么就要用等待队列。
顺便说一下,但不是完全确定:内核中所有的延时以及定时操作,无非是依赖于 jiffies、低精度timer、高精度timer、循环指令(已经知道一条指令的执行时间,通过运行N次指令达到延时效果)这几种机制。而jiffies又是依赖于低精度timer或者高精度timer(如果没有低精度timer)。