linux____内核延迟函数分析___操作

本文深入探讨了Linux内核提供的延时函数(ndelay, udelay, mdelay),并解释了它们的工作原理及在毫秒级以上延时时的局限性。同时,介绍了一种更为高效的延时方法,通过将延时时长设置为当前的jiffies加上所需时间,利用时间比较来实现精确延时。此外,文中还提到了msleep和ssleep等类函数的使用及受系统HZ和进程调度影响的精度限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自: http://blog.youkuaiyun.com/fdaopeng/article/details/6197385
分类: Linux   462人阅读  评论(0)  收藏  举报

linux内核提供3个函数分别进行纳秒,微妙和毫秒延时:

void ndelay(unsigned long nsecs);

void udelay(unsigned long usecs);

void mdelay(unsigned long msecs);

这3个函数的延时原理是忙等待,也就是说在延时的过程中并没有放弃cpu,根据cpu的频率进行一定次数的循环。

在内核中对于毫秒级以上的延时,最好不要直接使用mdelay函数,这将无谓的浪费cpu的资源,对于毫秒级以上的延时,内核提供了下列函数:

void msleep(unsigned int millisecs);

unsigned long msleep_interruptible(unsigned int milosecs);

void ssleep(unsigned int seconds);

注:受系统HZ以及进程调度的影响,msleep类似函数的精度是有限的。

1 长延时

在内核中,一个直观的延时的方法是将所要延迟的时间设置的当前的jiffies加上要延迟的时间,这样就可以简单的通过比较当前的jiffies和设置的时间来判断延时的时间时候到来。针对此方法,内核中提供了简单的宏用于判断延时是否完成。

time_after(jiffies,delay); /*此刻如果还没有到达延时的时间,则返回真,否则返回0*/

time_before(jiffies,delay);/*如果延时还没有完成,则返回真,否则返回0*/

 

下面两个函数可以将当前进程添加到等待队列中,从而在等待队列上睡眠,当超时发生时,进程将被唤醒:

sleep_on_timeout(wait_queue_head_t *q, unsigned long timeout);

interrupt_sleep_on_timeout(wait_queue_head_t *q, unsigned long timeout);

### Linux 内核中 `pick_eevdf` 函数的功能分析实现细节 #### 1. 功能概述 `pick_eevdf` 是 EEVDF(Earliest Eligible Virtual Deadline First)调度策略中的核心组件,负责从运行队列中选择下一个要执行的任务。它的主要功能是基于虚拟截止时间(Virtual Deadline)来决定哪个任务应该获得 CPU 资源[^1]。 EEVDF 的设计理念是在满足实时性需求的同时,兼顾系统的整体效率。为了达到这一目的,`pick_eevdf` 需要考虑以下几个方面: - **任务优先级**:高优先级任务通常会被赋予更早的虚拟截止时间。 - **CPU 使用情况**:已经消耗较多 CPU 时间的任务可能被推迟,以便让其他任务有机会运行。 - **动态调整**:随着系统状态的变化,`pick_eevdf` 不断重新评估每个任务的虚拟截止时间。 --- #### 2. 实现细节 ##### (1)虚拟截止时间的计算 虚拟截止时间是一个关键概念,决定了任务的选择顺序。其计算公式如下: \[ VD_i = \frac{C_i}{P_i} + A_i \] 其中: - \( VD_i \) 表示第 \( i \) 个任务的虚拟截止时间; - \( C_i \) 表示该任务已使用的 CPU 时间; - \( P_i \) 表示任务的优先级因子(数值越小表示优先级越高); - \( A_i \) 表示任务到达时间。 此公式的目的是将任务的实际运行时间和优先级结合起来,形成一个综合指标,用于比较不同任务之间的紧迫程度[^1]。 ##### (2)任务选择逻辑 `pick_eevdf` 的具体实现涉及遍历运行队列,并找到具有最小虚拟截止时间的任务。以下是其实现的关键部分: ```c struct task_struct *pick_eevdf(struct rq *rq) { struct task_struct *earliest_task = NULL; s64 min_vd = S64_MAX; // 遍历运行队列中的所有任务 list_for_each_entry(p, &rq->task_list, run_list) { s64 vd = calculate_virtual_deadline(p); if (vd < min_vd || (!earliest_task && p->state == TASK_RUNNING)) { min_vd = vd; earliest_task = p; } } return earliest_task; // 返回具有最早虚拟截止时间的任务 } s64 calculate_virtual_deadline(struct task_struct *p) { u64 ci = p->se.sum_exec_runtime; // 已使用的 CPU 时间 u64 pi = prio_to_weight[p->static_prio]; // 优先级权重 u64 ai = p->activation_time; // 到达时间 return div_u64(ci, pi) + ai; // 计算虚拟截止时间 } ``` 在此代码片段中: - `calculate_virtual_deadline` 函数实现了前述的虚拟截止时间计算公式。 - `pick_eevdf` 函数则通过遍历运行队列,找出具有最小虚拟截止时间的任务作为下一运行者。 --- #### 3. 应用场景与优势 ##### (1)应用场景 `pick_eevdf` 特别适合以下场景: - **实时系统**:需要严格控制任务延迟的情况,例如音视频处理、工业自动化等领域。 - **混合负载环境**:既有实时任务又有普通任务的情况下,EEVDF 可以很好地平衡两者的需求[^3]。 ##### (2)相比传统调度器的优势 相比于传统的 O(1) 调度器或其他调度算法(如 CFS),EEVDF 在某些场景下具备独特优势: - 更强的实时性支持:通过对虚拟截止时间的精确管理,EEVDF 能够更好地满足硬实时任务的要求。 - 自动化的资源分配:即使在高负载环境下,也能通过动态调整虚拟截止时间来避免饥饿现象的发生[^4]。 然而,这种灵活性也带来了额外的计算开销。因此,在纯批处理或非实时环境中,CFS 或许仍然是更好的选择。 --- #### 4. 总结 `pick_eevdf` 是一种高效的调度决策函数,能够在复杂的多任务环境中提供出色的性能表现。它通过引入虚拟截止时间的概念,成功解决了传统调度器中存在的许多问题,特别是在实时性和公平性之间取得了良好折衷。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值