Linux内核中的延时函数详解

内核中涉及的延时主要有两种实现方式:忙等待或者睡眠等待。前者阻塞程序,在延时时间到达前一直占用CPU,而后者是将进程挂起(置进程于睡眠状态并释放CPU资源)。所以,前者一般用在延时时间在毫秒以内的精确延时,后者用于延时时间在毫秒以上的长延时。为了充分利用 CPU 资源,使系统有更好的吞吐性能,在对延迟时间的要求并不是很精确的情况下,睡眠等待通常是值得推荐的。

1、忙等待短延时

内核中提供了如下3个函数用于纳秒、微秒和毫秒级的延时:

void ndelay(unsigned long nsecs); 
void udelay(unsigned long usecs); 
void mdelay(unsigned long msecs); //一般不建议直接使用mdelay()函数,这将无谓地耗费 CPU 资源

上述延迟的实现原理本质上是忙等待,它根据 CPU 频率进行一定次数的循环。其本质同如下代码:

void delay(unsigned int time) 
{ 
 while (time--); 
}

2、忙等待长延时函数

内核中进行延迟的一个很直观的方法是比较当前的 jiffies 和目标 jiffies(设置为当前 jiffies 加上时间间隔的 jiffies),直到未来的 jiffies 达到目标 jiffies。

  • 利用jiffies和time_befor实现延时100个jiffies和2秒的代码:
 /*延迟 100 个 jiffies*/ 
 unsigned long delay = jiffies + 100; 
 while (time_before(jiffies, delay)); 
 
 /*再延迟 2s*/ 
 unsigned long delay = jiffies + 2*HZ; 
 while (time_before(jiffies, delay)); 

其中,time_befor()只是一个函数宏,与其对应的还有一个time_after():

#define time_after(a,b) \ 
 (typecheck(unsigned long, a) && \ 
 typecheck(unsigned long, b) && \ 
 ((long)(b) - (long)(a) < 0)) 

#define time_before(a,b) time_after(b,a) 

3、睡眠短延时

3.1 sleep类延时函数

下述函数将使得调用它的进程睡眠参数指定的时间,受系统 HZ 和进程调度的影响,msleep()类似函数的精度是有限的。msleep()、ssleep()不能被打断,而msleep_interruptible()则可以被打断。

void msleep(unsigned int millisecs); 
unsigned long msleep_interruptible(unsigned int millisecs); 
void ssleep(unsigned int seconds); 

3.2 schedule类睡眠延时函数

signed long  schedule_timeout_interruptible(signed long timeout);

signed long  schedule_timeout_uninterruptible(signed long timeout) 

schedule_timeout()可以使当前任务睡眠指定的jiffies 之后重新被调度执行,它的实现原理是向系统添加一个定时器,在定时器处理函数中唤醒参数对应的进程。上一小节的sleep类函数的底层实现也是调用它实现的:

void msleep(unsigned int msecs) 
{ 
	unsigned long timeout = msecs_to_jiffies(msecs) + 1; 
	while (timeout) 
		timeout = schedule_timeout_uninterruptible(timeout); 
} 
 
unsigned long msleep_interruptible(unsigned int msecs) 
{ 
	unsigned long timeout = msecs_to_jiffies(msecs) + 1; 
	while (timeout && !signal_pending(current)) 
		timeout = schedule_timeout_interruptible(timeout); 
	return jiffies_to_msecs(timeout); //返回剩余的延时时间
}

signed long _ _sched schedule_timeout_interruptible(signed long timeout) 
{ 
	_ _set_current_state(TASK_INTERRUPTIBLE); //置进程状态为 TASK_INTERRUPTIBLE
	return schedule_timeout(timeout); 
} 
 
signed long _ _sched schedule_timeout_uninterruptible(signed long timeout) 
{ 
	_ _set_current_state(TASK_UNINTERRUPTIBLE); //置进程状态为 TASK_UNINTERRUPTIBLE
	return schedule_timeout(timeout); 
} 

3.3 sleep_on类,在等待队列上睡眠的延时函数

函数可以将当前进程添加到等待队列中,从而在等待队列上睡眠。当超时发生时,进程将被唤醒(后者可以在超时前被打断):

sleep_on_timeout(wait_queue_head_t *q, unsigned long timeout); 

interruptible_sleep_on_timeout(wait_queue_head_t*q, unsigned long timeout); 
  • 2
    点赞
  • 12
    收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:鲸 设计师:meimeiellie 返回首页
评论 4

打赏作者

Leon_George

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值