Linux内核中的Workqueue机制分析
1. 什么是workqueue
Linux中的workqueue(工作队列)主要是为了简化在内核创建线程而设计的。通过相应的工作队列接口,可以使开发人员只关心与特定功能相关的处理流程,而不必关心内核线程的创建、维护和销毁等工作(这样的工作对于一般人员来说是比较困难的,稍有不慎可能导致系统的崩溃),大大提高的系统的稳定性和扩展性。
我们可以通过调用workqueue的相关接口函数自动创建内核线程,此外它可以根据需求为每一个cpu核创建一个workqueue, 这对目前的多核并发提供了较好的支持。
2. workqueue的高频使用场合(尤其面试中)
Linux在处理中断的过程中,中断处理函数应尽快的完成,否则将会应用对其他中断的响应,从而影响整个系统的性能。但耗时的操作有时有必不可免,因此Linux为了解决这矛盾,将中断处理流程分成了中断上半部和中断下半部;
中断上半部: 主要完成紧急而又不耗时的工作
中断下半部:完成不紧急但比较耗时的操作。 下半部在执行过程中,中断被重新使能,因此此时可以响应新的中断,而正在执行的中断下半部被迫停止而去执行新的中断上半部,只有当没有新的中断发生时再去执行中断下半部处理流程。
这与workqueue(工作队列)有什么关系呢?
原因就在于workqueue经常用来处理中断下半部操作,相对于软中断和tasklet,这样做的优势有很多:
- workqueue是一个内核进程,工作在进程上下文,可以使用调度器;而软中断和tasklet则工作在中断上下文,不能使用引起调度的函数或者接口。
- workqueue作为一个单独的内核线程,可以进行延时或者休眠。
3. workqueue在内核中的组织结构
在workqueue中,涉及的比较重要的数据结构有三个,其组织关系可以如下图表示:
(这只是个简单的缩略图,其结构体其他成员未标出)

3.1 workqueue_struct 结构
struct workqueue_struct {
struct cpu_workqueue_struct *cpu_wq; /*用于挂接不同cpu核上的同一类工作队列*/
struct list_head list;
const char *name; /*工作队列名字*/
int singlethread; /*是否为单线程而不论有一个cpu核*/
int freezeable; /* Freeze threads during suspend */
};
3.2 cpu_workqueue_struct 结构
/*
* The per-CPU workqueue (if single thread, we always use the first
* possible cpu).
*/
struct cpu_workqueue_struct {
spinlock_t lock;
struct list_head worklist; /*工作列表,添加工作时放入此链表中*/
wait_queue_head_t more_work;
struct work_struct *current_work;/*从工作链表中取出的正在执行的工作*/
struct workqueue_struct *wq;/*指向上一级workqueue_struct目录*/
struct task_struct *thread; /*创建的线程*/
int run_depth; /* Detect run_workqueue() recursion depth */
}
3.3 work_struct 结构
workqueue中,三个结构体中,只有这个结构才是与开发常用的,上述两个数据结构及操作接口可以直接使用而无需我们进行开发或者修改。
struct work_struct {
atomic_long_t data; /*传入的数据*/
#define WORK_STRUCT_PENDING 0 /* T if work item pending execution */
#define WORK_STRUCT_FLAG_MASK (3UL)
#define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK)
struct list_head entry;
work_func_t func; /*完成工作的函数,如果需要参数,则使用data进行传递*/
};
4. workqueue的函数接口
| 序号 | 接口函数 | 说明 |
|---|---|---|
| 1 | create_workqueue | 用于创建一个workqueue队列,为系统中的每个CPU都创建一个内核线程。输入参数:@name:workqueue的名称 |
| 2 | create_singlethread_workqueue | 用于创建workqueue,只创建一个内核线程。 输入参数:@name:workqueue名称 |
| 3 | destroy_workqueue | 释放workqueue队列。输入参数:@ workqueue_struct:需要释放的workqueue队列指针 |
| 4 | schedule_work | 调度执行一个具体的任务,执行的任务将会被挂入Linux系统提供的workqueue——keventd_wq输入参数:@ work_struct:具体任务对象指针 |
| 5 | schedule_delayed_work | 延迟一定时间去执行一个具体的任务,功能与schedule_work类似,多了一个延迟时间,输入参数:@work_struct:具体任务对象指针; @delay:延迟时间 |
| 6 | queue_work | 调度执行一个指定workqueue中的任务。输入参数:@ workqueue_struct:指定的workqueue指针**@work_struct**:具体任务对象指针 |
| 7 | queue_delayed_work | 延迟调度执行一个指定workqueue中的任务,功能与queue_work类似,只是多了一个delay参数。 |
下面简单介绍下上述几个接口的实现逻辑:
5. workqueue的初始化

6. 将工作添加到workqueue中

7.workqueue的销毁

Linux内核中的Workqueue机制分析的更多相关文章
- Linux内核中的信号机制--一个简单的例子【转】
本文转载自:http://blog.csdn.net/ce123_zhouwei/article/details/8562958 Linux内核中的信号机制--一个简单的例子 Author:ce123 ...
- Linux内核中SPI总线驱动分析
本文主要有两个大的模块:一个是SPI总线驱动的分析 (研究了具体实现的过程): 另一个是SPI总线驱动的编写(不用研究具体的实现过程). 1 SPI概述 SPI是英语Serial Peripheral ...
- 浅析linux内核中的idr机制
idr在linux内核中指的就是整数ID管理机制,从本质上来说,这就是一种将整数ID号和特定指针关联在一起的机制.这个机制最早是在2003年2月加入内核的,当时是作为POSIX定时器的一个补丁.现在, ...
- 再谈Linux内核中的RCU机制
转自:http://blog.chinaunix.net/uid-23769728-id-3080134.html RCU的设计思想比较明确,通过新老指针替换的方式来实现免锁方式的共享保护.但是具体到 ...
- Linux内核中TCP SACK机制远程DoS预警通告
漏洞描述 2019年6月18日,RedHat官网发布报告:安全研究人员在Linux内核处理TCP SACK数据包模块中发现了三个漏洞,CVE编号为CVE-2019-11477.CVE-2019-114 ...
- armv8(aarch64)linux内核中flush_dcache_all函数详细分析【转】
转自:http://blog.csdn.net/qianlong4526888/article/details/12062809 版权声明:本文为博主原创文章,未经博主允许不得转载. /* * __ ...
- linux内核中sys_poll()的简化分析
app:poll or select; kernel: sys_poll(); do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,st ...
- armv8(aarch64)linux内核中flush_dcache_all函数详细分析
/* * __flush_dcache_all() * Flush the wholeD-cache. * Corrupted registers: x0-x7, x9-x11 */ ENTRY( ...
- Linux内核中锁机制之RCU、大内核锁
在上篇博文中笔者分析了关于完成量和互斥量的使用以及一些经典的问题,下面笔者将在本篇博文中重点分析有关RCU机制的相关内容以及介绍目前已被淘汰出内核的大内核锁(BKL).文章的最后对<大话Linu ...
随机推荐
- 小白学习vue第五天(理解使用组件开发,组件第一弹)
组件怎么从创建到使用? 第一步创建组件构造器对象 感觉个人理解就是创建一个模板,和创建MongoDB数据模板相似 const cpnC = Vue.extend({ template: ` <d ...
- 自学vue第二天,从入门到放弃(生命周期的理解)
生命周期的理解 beforeCreate 创建前 数据还没有监听,没有绑定到vue对象实例,同时也没有挂载对象 没有数据也没有方法 created 在创建后 数据和方法已经 data数据已经绑定好了 ...
- TCP可靠传输
1. TCP 可靠性如何保证? 信道可靠:用三次握手.四次挥手保证连接正确: 数据正确:分区编号.校验和.超时重传: 传输控制:流量控制.拥塞控制 2. 重传机制 TCP可靠传输方式是序列号与确认应答 ...
- Terracotta 2.7.2 Admin Console Guide
http://www.terracotta.org/confluence/display/docs27/Admin+Console+Guide#AdminConsoleGuide-Roots
- docker安装完权限问题
在用户权限下docker 命令需要 sudo 否则出现以下问题 通过将用户添加到docker用户组可以将sudo去掉,命令如下 sudo groupadd docker #添加docker用户组 su ...
- SpringBoot启动标识修改
在src/main/resources下新建一个banner.txt ${AnsiColor.BRIGHT_RED} ///////////////////////////////////////// ...
- js简单实现拦截访问指定网页
最近闲的无事,写个脚本玩玩,实现拦截访问指定网址 浏览器插件 要想实现这个功能,就要自定义一个浏览器插件 最简单的浏览器插件有两个文件,分别是manifest.json和**.js.首先新建一个文件夹 ...
- COM笔记-引用计数
参考网站:https://www.cnblogs.com/fangyukuan/archive/2010/06/06/1752621.html com组件将维护一个称作是引用计数的数值.当客户从组件取 ...
- 【spring 注解驱动开发】spring自动装配
尚学堂spring 注解驱动开发学习笔记之 - 自动装配 自动装配 1.自动装配-@Autowired&@Qualifier&@Primary 2.自动装配-@Resource& ...
- Windows下NodeJS安装与npm环境变量配置
node.js下载:https://nodejs.org/en/download/ 参考:https://www.jianshu.com/p/812de13f1276 1.安装过程基本直接" ...