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 ...
随机推荐
- 获取windows 操作系统下的硬件或操作系统信息等
奇怪的工作,制作的是一款办公应用软件,领导却要求我统计用户计算机的物理信息,什么CPU的型号.核心数,什么内存信息等各种乱七八糟的用户信息.我想问,现在用户的信息就这么没有隐私性了么?想获取就获取传递 ...
- Blazor 路由及导航开发指南
翻译自 Waqas Anwar 2021年4月2日的文章 <A Developer's Guide To Blazor Routing and Navigation> [1] 检查传入的请 ...
- Linux常见问题解决方案
1.Kali2020添加BCM43142的网卡驱动 来源:https://www.fujieace.com/kali-linux/wifi-drive.html 我只是执行了第三步:安装网卡驱动,即: ...
- SpringBoot | 3.3 整合MyBatis-Plus
目录 前言 1. 什么是MyBatis-Plus 1.1 BaseMapper接口 1.2 IService接口 2. 整合MyBatis-Plus以及CRUD功能 2.1 导入场景依赖 2.2 CR ...
- MySQL学习02(操作数据库)
操作数据库 结构化查询语句分类 名称 解释 命令 DDL(数据库定义语言) 定义和管理数据对象,例如数据库和数据表 create.drop.alter DML(数据操作语言) 用于操作数据库对象中所包 ...
- SpringMVC学习04(数据处理及跳转)
4.数据处理及跳转 4.1结果跳转方式 4.1.1 ModelAndView 设置ModelAndView对象 , 根据view的名称 , 和视图解析器跳到指定的页面 . 页面 : {视图解析器前缀} ...
- netty系列之:自定义编码和解码器要注意的问题
目录 简介 自定义编码器和解码器的实现 ReplayingDecoder 总结 简介 在之前的系列文章中,我们提到了netty中的channel只接受ByteBuf类型的对象,如果不是ByteBuf对 ...
- Python语言系列-07-面向对象2
重构父类__init__方法 #!/usr/bin/env python3 # author:Alnk(李成果) # 需求:Dog类要新增一个实例属性,但是Cat类不需要 class Animal(o ...
- 泛微OA e-cology 数据库接口信息泄露学习
泛微OA e-cology 数据库接口信息泄露 漏洞信息 攻击者可通过存在漏洞的页面直接获取到数据库配置信息.如果攻击者可直接访问数据库,则可直接获取用户数据,甚至可以直接控制数据库服务器:会将当前连 ...
- LuoguP3167通配符匹配
题意 本题的意思就是给出一段带有 $ ? $ 与 \(*\) 的字符串 (在下面称为\(s\)), $ ? $ 必须占据一个字符位置, \(*\) 可以占据任意位置, 求下面给出几段(在下面称为\(s ...