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

Linux驱动开发八股文:工作队列(Workqueue)

📚 Linux 驱动开发笔记:工作队列 (Workqueue)

一、 核心定义

工作队列是 Linux 内核中断下半部(Bottom Half)的一种重要机制。它允许你将耗时的、需要等待资源或可能导致休眠的任务,从中断处理函数(ISR)中推迟到稍后的进程上下文中执行。

  • 关键特性:运行于进程上下文,可以休眠
  • 执行主体:内核线程(如kworker/0:2)。

二、 为什么需要工作队列? (对比 Tasklet)

在内核中,中断下半部主要有两种选择,它们的区别在于“执行环境”:

特性Tasklet工作队列 (Workqueue)
执行上下文中断(软中断)上下文进程上下文
能否休眠绝不可以(会系统崩溃)可以(如使用msleep
访问用户空间不可以不可以(虽然在进程上下文,但没有用户页表)
优先级极高,仅次于硬中断较低,由调度器决定
代表身份借用当前进程的“皮”拥有独立的内核线程 (kworker)

三、 工作队列的运作机制

  1. 提交任务:驱动在 ISR 中通过schedule_work函数提交一个work_struct
  2. 排队等待:该任务进入系统默认的工作队列链表。
  3. 唤醒线程:内核唤醒对应的内核线程(kworker)。
  4. 执行任务kworker线程从链表中取出任务,调用你编写的处理函数。
  5. 结束/调度:处理函数完成后,kworker线程继续处理下一个任务,或者进入睡眠。

四、 核心 API 与编程步骤

1. 定义工作结构体与处理函数

处理函数的参数是结构体本身,通常通过container_of获取私有数据。

struct work_struct my_work; void my_work_func(struct work_struct *work) { // 这里可以休眠! // printk("current->comm: %s, pid: %d\n", current->comm, current->pid); }
2. 初始化 (Init)

probe函数中完成,将函数指针绑定到结构体。

// 动态初始化 INIT_WORK(&gpio_key->work, my_work_func); // 或者静态定义 // DECLARE_WORK(name, function);
3. 调度 (Schedule)

在中断上半部(ISR)中调用,触发异步执行。

static irqreturn_t gpio_key_isr(int irq, void *dev_id) { schedule_work(&gpio_key->work); // 只是挂入队列,不阻塞 return IRQ_HANDLED; }

五、 实验现象深度解析

根据实验日志:

[165328.733643] {WORK_FUNC:}the process is kworker/0:2, its pid is 1722
  1. 身份证明current->commkworker/0:2,证明了工作队列不再是“借用”别人的身份,而是由内核专属的“工人”线程在干活。
  2. PID 1722:这是一个真实的进程 ID。在 Linux 中,凡是有 PID 的都能被调度器控制,这就是它为什么可以休眠的根本原因。
  3. 时序关系:日志中TASKLET总是先于WORK_FUNC打印。这是因为 Tasklet 优先级更高,在中断返回的瞬间执行;而 Workqueue 需要等待调度器切换到kworker线程,存在毫秒级的调度延迟。

六、 注意事项与避坑指南

  1. 顺序阻塞:默认的工作队列由同一个kworker线程依序处理。如果你在一个 Work 函数里写了while(1)或休眠太久,会堵塞同一个队列里的其他工作
  2. 重入性:如果在 Work 还没执行完时又发生了中断并schedule_work,内核通常不会重复启动同一个 Work 实例,它会等待当前运行的结束后再决定是否再次触发。
  3. API 演进:4.x 以后内核引入了CMWQ (Concurrency Managed Workqueue),它能更聪明地在多核之间分配任务,避免单个耗时任务卡死整个 CPU 的工作队列。

七、 总结:何时选择工作队列?

  • 任务很重(如:读取 1MB 的 Flash 数据)。
  • 需要等待(如:等待某个信号量、互斥锁)。
  • 需要延时(如:逻辑要求按键按下后等待 100ms 再读取)。
http://www.jsqmd.com/news/240860/

相关文章:

  • S32DS使用手把手教程:从零实现CAN通信配置
  • Linux应用与驱动开发:mmap和内存映射
  • Day 34:【99天精通Python】单元测试 (Unittest) - 给代码上个保险
  • 强烈安利10个AI论文软件,MBA毕业论文轻松搞定!
  • Day 35:【99天精通Python】综合实战 - 爬虫与数据分析可视化(上) - 数据采集与入库
  • 多FDCAN接口同步配置实战:双通道并行通信实现
  • Figma中文界面本地化:设计师专属的语言解决方案
  • Day 36:【99天精通Python】综合实战 - 爬虫与数据分析可视化(下) - 让数据“说话“
  • 导师推荐!8个AI论文平台测评:研究生开题报告全攻略
  • Intel平台嵌入式SPI通信:新手教程
  • Doris与Trino集成:统一SQL大数据查询引擎
  • 大模型微调技术详解:从全参数微调到RLHF的演进与应用
  • 学Simulink——基础储能管理场景实例:基于Simulink的多时间常数储能配置优化仿真
  • Day 38:【99天精通Python】线程池与进程池 - 优雅地管理并发
  • “死了么”App爆火,我发现了个安卓版,代码开源!
  • Figma中文插件完全配置指南:告别英文界面困扰
  • 基于Simulink的多时间常数储能配置优化仿真
  • 基于深度学习的森林火灾识别系统(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)
  • 基于YOLOv8的小麦田间病害识别项目|完整源码数据集+PyQt5界面+完整训练流程+开箱即用!
  • 多语言界面在screen中的实现:项目应用
  • 基于Simulink的混合PO与INC切换MPPT策略仿真
  • 学长亲荐8个一键生成论文工具,专科生毕业论文必备!
  • RHEL9系统部署与Linux命令操作实验报告
  • 《嵌入式操作系统》_在ubuntu系统中使用wine环境安装source insight_20260113
  • STM32调试技巧:Keil MDK实用操作指南
  • AI架构的云原生设计:AI应用架构师如何利用云服务优化架构?
  • 大数据数据服务在物流行业的应用
  • AI智能体(Agent)全解析+代码示例
  • 大语言模型完整技术栈:从理论到实践的全面指南
  • 无需本地安装!Linux服务器上用WPS办公,还能远程访问?这招太实用了