Linux驱动开发中的中断和等待队列
主要目标降低cpu占用率今天来讲一下Linux驱动开发中的中断和等待队列。这两个东西分别是干嘛的呢首先学过mcu的朋友对中断一定不会陌生它的作用就是当中断触发时打断cpu当前执行的任务来执行中断的操作。当中断任务执行结束后cpu再继续执行之前的任务。那等待队列是干啥的呢类似于mcu的信号量等待一个触发的条件再让cpu来执行。但这俩又不完全一样它们在“同步”和“阻塞”的目的上是相似的。MCU 中的信号量/标志位轮询‌在裸机或 RTOS 中你通常设置一个全局变量 key_pressed 0。主循环不断检查 if (key_pressed 1)。如果为 0主循环继续跑其他代码或进入低功耗模式WFI。这本质上是一种‌主动查询‌或‌基于标志位的协作式调度‌。‌Linux 等待队列‌它是一种‌内核级的进程休眠机制‌。当 read 发现没数据时它不是简单地返回或继续跑循环而是告诉内核“把我这个进程挂起Remove from CPU scheduler放到这个队列里睡觉直到有人叫醒我”。‌核心区别‌‌主动性 vs 被动性‌MCU 信号量通常需要你在主循环里‌主动去查‌除非你用 RTOS 的任务挂起 API那才更像等待队列。Linux 等待队列是‌被动休眠‌。进程调用 wait_event 后它就彻底从 CPU 调度器中消失了‌完全不占用 CPU 时间片‌直到被唤醒。‌上下文切换‌MCU 中改变标志位通常不涉及复杂的上下文保存/恢复除非触发任务切换。Linux 中wake_up 会触发内核调度器进行完整的进程上下文切换保存当前寄存器、加载被唤醒进程的寄存器等开销比 MCU 大但功能更强支持多进程、权限管理、信号处理等。‌结论‌你可以把等待队列理解为 ‌“RTOS 中带有条件判断的任务挂起Task Suspend with Condition”‌而不是简单的二进制信号量。它让进程在没有数据时“彻底消失”从而极大降低 CPU 负载。知道了这两个东西分别是干啥的我们能用他们来做什么呢降低cpu的占用率。‌降低 CPU 占用‌依靠‌等待队列‌让无事件时的进程彻底休眠不再消耗 CPU 周期依靠‌中断‌让 CPU 仅在硬件事件发生时才介入以按键为例我们设置一个检测按键上升沿的中断然后在read函数里设置好等待队列条件为假让等待队列挂起当按键被按下触发中断中断服务函数被执行此时等待队列条件为真等待队列被释放释放后继续执行read函数里操作把读取到的值传递到应用层。在上述过程中cpu只有在中断触发后才分配时间片给read函数其他时间都不再执行read函数这就会大幅降低cpu的占用率。在这个过程中cpu在read函数中遇到等待队列函数后就不再继续执行read函数了但是如何让等待队列释放唤醒read函数继续执行呢原理是什么也就是说既然 read 函数在休眠没分到时间片哪是谁检测到按键并告诉 CPU 执行 read这是初学者最大的误区‌并不是“谁告诉 CPU 去执行 read 函数”而是“硬件中断打断了 CPU 当前的工作内核在中断处理程序中唤醒了休眠的 read 进程”。‌这里有一个关键的硬件机制‌GPIO 控制器的中断功能‌。详细流程拆解休眠状态Read 进程‌应用层调用 read()。驱动发现没按键按下调用 wait_event_interruptible()。关键点‌此时read 函数的代码执行‌暂停‌了。这个进程的状态变为 TASK_INTERRUPTIBLE可中断休眠。CPU 在干嘛‌ CPU 此时正在运行‌其他进程‌比如桌面界面、网络服务、或者空闲任务 idle。它完全不知道 read 的存在也不分配时间片给 read。硬件事件发生按键按下‌你按下了按键GPIO 引脚电平发生变化例如从低变高。谁检测到的‌ 不是 CPU也不是驱动程序而是 ‌SoC 内部的 GPIO 控制器硬件电路‌。GPIO 控制器内部有一个比较器或边沿检测电路它独立于 CPU 核心运行。一旦检测到电平跳变它会向 CPU 的‌中断控制器如 GIC‌发送一个电信号Interrupt Request, IRQ。中断响应CPU 被硬件打断‌CPU 收到中断信号后无论它当前正在运行什么代码哪怕是空闲任务都会‌立即暂停‌当前工作。CPU 硬件自动保存当前上下文跳转到预先注册好的‌中断处理函数ISR, Interrupt Service Routine‌。注意‌此时执行的代码是驱动中注册的 irq_handler‌而不是‌ read 函数。中断处理与唤醒关键步骤‌在 irq_handler 中驱动代码执行以下操作读取 GPIO 状态确认是按键按下可能包含消抖逻辑。将键值存入全局缓冲区。设置条件标志 data_available 1。调用 wake_up_interruptible(my_wait_queue)‌。wake_up 做了什么‌ 它通知内核调度器“等待在 my_wait_queue 上的那个进程也就是之前休眠的 read 进程现在条件满足了把它状态改为 TASK_RUNNING就绪态放入调度队列。”重要‌wake_up ‌并没有立即执行‌ read 函数的剩余代码。它只是把 read 进程标记为“可以运行了”。进程恢复与数据返回‌中断处理函数执行完毕CPU 返回到刚才被打断的地方可能是空闲任务或其他进程继续运行。在下一次‌内核调度时机‌例如中断返回时、时间片用完时调度器发现 read 进程现在是“就绪态”且优先级合适。调度器切换上下文‌恢复 read 函数的执行‌。wait_event_interruptible 宏检测到 data_available 为真于是从休眠中返回。read 函数继续执行后续代码copy_to_user 将数据发给应用层然后返回。总结回答上面的疑问是谁检测到按键‌是 ‌GPIO 硬件控制器‌。它独立于 CPU 软件运行专门监控引脚电平。是谁告诉 CPU要去执行中断服务函数了‌是 ‌中断控制器GIC‌ 通过硬件电信号通知 CPU 核心。CPU 去执行 read 函数了吗‌没有直接执行 read。‌ CPU 先去执行‌中断服务函数ISR‌。在 ISR 中内核通过 wake_up 机制‌唤醒‌了休眠的 read 进程。随后由‌内核调度器‌决定何时恢复 read 进程的运行。形象比喻‌Read 进程‌像一个在候诊室睡觉的病人休眠。GPIO 硬件‌像门口的门铃按钮。中断‌病人按铃硬件触发护士中断处理程序听到铃声。Wake_up‌护士走到候诊室把病人的状态牌从“睡觉”翻成“待诊”唤醒但护士不会立刻给病人看病而是回到前台。调度器‌医生CPU看完手头的急诊中断处理完查看待诊列表发现这个病人醒了于是叫他的号上下文切换病人开始看病read 函数继续执行并返回数据。在这个过程中病人在睡觉时完全不占用医生的时间CPU 资源只有按铃和处理的那一瞬间需要医生介入。这就是为什么它能降低 CPU 占用率。代码示例此示例中的按键为双边沿触发#include linux/kernel.h#include linux/module.h#include linux/fs.h#include linux/gpio.h#include linux/uaccess.h#include linux/platform_device.h#include linux/of.h#include linux/of_gpio.h#include linux/miscdevice.h//1、添加头文件#include linux/irq.h#include linux/interrupt.h//9、添加等待队列头文件#include linux/wait.h#include linux/sched.h//10、申请等待队列列头DECLARE_WAIT_QUEUE_HEAD(mywait);//杂项设备开发框架linux设备树和平台总线开发框架struct miscdevice misc;struct file_operations ops;int key1,key2;//3、定义中断号int irq1;int irq2;int value;int ret;//12、定义等待队列条件int wait_flag;// 5、定义中断服务函数irqreturn_t myirqfunc(int irq, void *arg){if (irq irq1){value 1;}else if (irq irq2){value 2;}//进入中断说明按键完成一次按下// value 1; //先赋值再释放//14、等待队列条件置为真wait_flag 1;//15、等待队列释放wake_up_interruptible(mywait);return 0;}//1、定义open文件接口int myopen(struct inode *inode,struct file *file){gpio_request(key1,key1);gpio_direction_input(key1);gpio_request(key2,key2);gpio_direction_input(key2);// 2、获取中断号// irq1 gpio_to_irq(key1);// 使能中断 --- 对于当前板子不需要// 4、注册中断服务函数ret request_irq(irq1,myirqfunc,IRQ_TYPE_EDGE_BOTH,irq1,NULL);ret request_irq(irq2,myirqfunc,IRQ_TYPE_EDGE_BOTH,irq2,NULL);return 0;}//3、定义close文件接口int myclose(struct inode *inode, struct file *file){// 释放中断服务函数free_irq(irq1,NULL);free_irq(irq2,NULL);// 失能中断 --- 对于当前板子不需要return 0;}//定义read文件接口ssize_t myread(struct file *file, char __user *buf, size_t size, loff_t *offt){//13、等待队列条件清0wait_flag 0;//11、等待队列挂起wait_event_interruptible(mywait ,wait_flag);//程序会一直停在这个分号后ret copy_to_user(buf,value,size);value 0;return 0;}//4、定义probe函数int myprobe(struct platform_device *pdev){printk(匹配成功\n);//8、获取节点信息key1 of_get_named_gpio(pdev-dev.of_node,gpios,0);key2 of_get_named_gpio(pdev-dev.of_node,gpios,1);//8、设备树获取中断号irq1 platform_get_irq(pdev,0);irq2 platform_get_irq(pdev,1);ops.owner THIS_MODULE;//2、把open加入核心结构体ops.open myopen;//4、把release加入核心结构体ops.release myclose;//把read加入核心结构体ops.read myread;misc.fops ops;misc.minor 255;misc.name key;misc_register(misc);return 0;};//5、定义remove函数int myremove(struct platform_device *pdev){misc_deregister(misc);return 0;};//6、定义匹配核心结构体struct of_device_id myid {.compatible key-platdata,};// 3、定义驱动端核心结构体struct platform_driver pdrv {.probe myprobe,.remove myremove,.driver.owner THIS_MODULE,.driver.name 1012,.driver.of_match_table myid,};static int __init myinit(void){// 2、驱动端注册platform_driver_register(pdrv);return 0;}static int __exit myexit(void){// 7、驱动端注销platform_driver_unregister(pdrv);}module_init(myinit);module_exit(myexit);MODULE_LICENSE(GPL);设备树文件xyd_key: xyd-key {compatible key-platdata;gpios gpio1 RK_PA7 GPIO_ACTIVE_LOW,gpio1 RK_PB1 GPIO_ACTIVE_LOW;interrupt-parent gpio1;interrupts RK_PA7 IRQ_TYPE_EDGE_BOTH,RK_PB1 IRQ_TYPE_EDGE_BOTH;status okay;};

相关新闻

商品三级类目设计:从Excel导入到树形查询的工程实践

商品三级类目设计:从Excel导入到树形查询的工程实践

简介:这是一份面向iOS开发初学者与电商系统开发者的商品三级类目实现示例,基于Objective-C与Storyboard构建,帮助理解类目树在移动端的前端展示与数据组织方式。压缩包共23个文件,约54KB,包含7个.m实现文件、4个.h头文…

2026/10/14 21:27:09 阅读更多 →
Polyspace静态分析实战:嵌入式C代码形式化验证指南

Polyspace静态分析实战:嵌入式C代码形式化验证指南

简介:本资源是一份面向嵌入式软件开发工程师与安全验证人员的Polyspace静态分析工具实操指南,聚焦C/C代码鲁棒性提升与运行时错误防控。内容覆盖Polyspace Bug Finder与Code Prover双模块的核心功能对比、工程创建、源码导入、分析配置、结果解读&#x…

2026/10/14 21:27:09 阅读更多 →
发票、流水、社保——被点名前,请自查这三样

发票、流水、社保——被点名前,请自查这三样

这两天,济南不少老板手机上弹出了风险提示。先别慌——它不是罚单,是一次体检报告。先说它怎么来的。不是有人举报你,也不是要来查你。是系统把你申报的数据、开票的数据、银行的数据做了交叉比对,几个指标对不上,自动…

2026/10/14 21:27:09 阅读更多 →

最新新闻

Natron ErodeSmooth 节点完全指南:归一化功率加权腐蚀/膨胀滤镜的参数解析与源码级解读

Natron ErodeSmooth 节点完全指南:归一化功率加权腐蚀/膨胀滤镜的参数解析与源码级解读

音视频视频处理图形学桌面应用 【免费下载链接】Natron Open-source video compositing software. Node-graph based. Similar in functionalities to Adobe After Effects and Nuke by The Foundry. 项目地址: https://gitcode.com/gh_mirrors/na/Natron 点击查看 …

2026/10/15 3:32:41 阅读更多 →
GreaterWMS 移动端构建实战:基于 Quasar CLI 与 Cordova 的 Android 打包安装全流程

GreaterWMS 移动端构建实战:基于 Quasar CLI 与 Cordova 的 Android 打包安装全流程

后端前端企业应用 【免费下载链接】GreaterWMS This Inventory management system is the currently Ford Asia Pacific after-sales logistics warehousing supply chain process . After I leave Ford , I start this project . You can share your vacant warehouse space, …

2026/10/15 3:32:41 阅读更多 →
从Apollo-11代号项目到可复现工程:逆向拆解与改造指南

从Apollo-11代号项目到可复现工程:逆向拆解与改造指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 3:32:41 阅读更多 →
rospack depends1 报错排查:ROS依赖查询与环境变量配置实战

rospack depends1 报错排查:ROS依赖查询与环境变量配置实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 3:32:41 阅读更多 →
Vue2多页面应用模板:从vue.config.js到webpack配置的完整实践

Vue2多页面应用模板:从vue.config.js到webpack配置的完整实践

简介:Vue 2.0多页面应用模板面向需要同时维护多个独立页面的前端开发场景,旨在解决传统单页应用在官网、专题页等多入口项目中重复搭建构建流程、难以统一工程化配置的问题。资源包共32个文件,压缩后仅31KB,包含15个JavaScript脚本…

2026/10/15 3:32:41 阅读更多 →
NC65销售订单批量导入实战:从数据清洗到SQL脚本全攻略

NC65销售订单批量导入实战:从数据清洗到SQL脚本全攻略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 3:31:40 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →