Linux 内核工作队列之work_struct 学习总结
前言
编写Linux驱动的时候对于work_struct的使用还是很普遍的,很早之前就在阅读驱动源码的时候就看到了它的踪影,根据其命名大概知道了它的具体作用,但是仍然不知所以,同时,伴随出现的还有delayed_work以及workqueue_struct,抱着知其然并知其所以然的态度,在这里归纳总结一下work_struct,以及如何在驱动中使用,因为工作队列相对来说比较复杂,篇幅和能力有限,只能介绍相对重要的部分。
workqueue
内核里一直运行类似worker thread,它会对工作队列中的work进行处理,大致的工作流程原理可以参考下图所示;

在这里的work则是work_struct变量,并且绑定一个执行函数——typedef void (*work_func_t)(struct work_struct *work);。在worker thread中会对非空的工作队列进行工作队列的出队操作,并运行work绑定的函数。
work_struct
work_struct的数据结构如下,暂时我们还无法关注其原理,只关注如何去开启一个work
#include <linux/include/workqueue.h>
typedef void (*work_func_t)(struct work_struct *work);
struct work_struct {
atomic_long_t data;
struct list_head entry;
work_func_t func;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
通过数据结构可以知道,每当我们定义一个work_struct变量的时候,需要绑定一个work_func_t类型的函数指针。
| 函数 | 功能 |
|---|---|
| INIT_WORK(_work, _func) | 初始化一个work |
| INIT_WORK_ONSTACK(_work, _func) | 在栈上初始化一个work |
| flush_work(struct work_struct *work); | 销毁一个work |
| schedule_work(struct work_struct *work) | 调度一个work开始运行 |
例程
下面写了 一个demo,模块初始化之后会每隔5秒调度work开始运行,最终demo_work_func会运行规定的次数,并打印传递的参数和进程信息。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/time.h>
#include <linux/jiffies.h>
#include <linux/workqueue.h>
#include <linux/slab.h> //kmalloc kfree
#include <linux/sched.h>
#include <linux/delay.h>
static char data[] = "test for demo work";
struct work_ctx{
struct work_struct real_work;
char *str;
int arg;
}work_ctx;
struct work_ctx *demo_work;
static void demo_work_func(struct work_struct *work){
struct work_ctx *temp_work = container_of(work,struct work_ctx,real_work);
printk(KERN_INFO "[work]=> PID: %d; NAME: %s\n", current->pid, current->comm);
printk(KERN_INFO "[work]=> sleep 1 seconds\n");
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1 * HZ); //Wait 1 seconds
printk(KERN_INFO "[work]=> data is: %d %s\n", temp_work->arg,temp_work->str);
}
static int __init demo_thread_init(void){
int count = 10;
demo_work = kmalloc(sizeof(*demo_work),GFP_KERNEL);
INIT_WORK(&demo_work->real_work, demo_work_func);
demo_work->str = data;
while(count--){
msleep(5000);
demo_work->arg = count;
schedule_work(&demo_work->real_work);
}
return 0;
}
module_init(demo_thread_init);
static void __exit demo_thread_exit(void){
flush_work(&demo_work->real_work);
kfree(demo_work);
}
module_exit(demo_thread_exit);
MODULE_LICENSE("GPL");
运行结果
[ 8.500146] [work]=> PID: 37; NAME: kworker/0:1
[ 8.500216] [work]=> sleep 1 seconds
[ 9.499783] [work]=> data is: 9 test for demo work
[ 13.503165] [work]=> PID: 37; NAME: kworker/0:1
[ 13.503213] [work]=> sleep 1 seconds
[ 14.503122] [work]=> data is: 8 test for demo work
[ 18.506493] [work]=> PID: 37; NAME: kworker/0:1
[ 18.506534] [work]=> sleep 1 seconds
[ 19.506460] [work]=> data is: 7 test for demo work
[ 23.509833] [work]=> PID: 37; NAME: kworker/0:1
[ 23.509874] [work]=> sleep 1 seconds
[ 24.510060] [work]=> data is: 6 test for demo work
[ 28.513161] [work]=> PID: 37; NAME: kworker/0:1
[ 28.513206] [work]=> sleep 1 seconds
[ 29.513121] [work]=> data is: 5 test for demo work
[ 33.516502] [work]=> PID: 37; NAME: kworker/0:1
[ 33.516545] [work]=> sleep 1 seconds
[ 34.516452] [work]=> data is: 4 test for demo work
[ 38.519819] [work]=> PID: 37; NAME: kworker/0:1
[ 38.519860] [work]=> sleep 1 seconds
[ 39.519782] [work]=> data is: 3 test for demo work
[ 43.523151] [work]=> PID: 37; NAME: kworker/0:1
[ 43.523191] [work]=> sleep 1 seconds
[ 44.523117] [work]=> data is: 2 test for demo work
[ 48.526495] [work]=> PID: 37; NAME: kworker/0:1
[ 48.526542] [work]=> sleep 1 seconds
[ 49.526444] [work]=> data is: 1 test for demo work
[ 53.539699] [work]=> PID: 37; NAME: kworker/0:1
[ 53.539763] [work]=> sleep 1 seconds
[ 54.542925] [work]=> data is: 0 test for demo work
参考
https://www.oreilly.com/library/view/understanding-the-linux/0596005652/ch04s08.html
https://kukuruku.co/post/multitasking-in-the-linux-kernel-workqueues/
Linux 内核工作队列之work_struct 学习总结的更多相关文章
- LINUX内核分析第一周学习总结——计算机是如何工作的
LINUX内核分析第一周学习总结——计算机是如何工作的 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/course/ ...
- LINUX内核分析第二周学习总结——操作系统是如何工作的
LINUX内核分析第二周学习总结——操作系统是如何工作的 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/course ...
- LINUX内核分析第四周学习总结——扒开系统调用的“三层皮”
LINUX内核分析第四周学习总结--扒开系统调用的"三层皮" 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>MOOC ...
- linux内核分析第四周学习笔记
linux内核分析第四周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...
- Linux内核分析第二周学习笔记
linux内核分析第二周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...
- linux内核分析第一周学习笔记
linux内核分析第一周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...
- Linux内核的ioctl函数学习
Linux内核的ioctl函数学习 来源:Linux公社 作者:Linux 我这里说的ioctl函数是在驱动程序里的,因为我不知道还有没有别的场合用到了ioctl, 所以就规定了我们讨论的范围.为什 ...
- Linux内核分析第一周学习博客 --- 通过反汇编方式学习计算机工作过程
Linux内核分析第一周学习博客 通过反汇编方式学习计算机工作过程 总结: 通过这次对一个简单C程序的反汇编学习,我了解到计算机在实际工作工程中要涉及大量的跳转指针操作.计算机通常是顺序执行一条一条的 ...
- Linux内核分析第二周学习博客——完成一个简单的时间片轮转多道程序内核代码
Linux内核分析第二周学习博客 本周,通过实现一个简单的操作系统内核,我大致了解了操作系统运行的过程. 实验主要步骤如下: 代码分析: void my_process(void) { int i = ...
随机推荐
- work of 1/4/2016
part 组员 今日工作 工作耗时/h 明日计划 工作耗时/h UI 冯晓云 修改UI增强显示鲁棒 6 完成UI页面切换部分 ...
- D. AB-string
https://codeforces.com/contest/1238/problem/D 题目大意:统计good string的个数,good string的定义,给定的字符串中含有回文段落, 题解 ...
- golang 基础 map及工厂函数
Map是一种数据结构,是一个集合,用于存储一系列无序的键值对.它基于键存储的,键就像一个索引一样,这也是Map强大的地方,可以快速快速检索数据,键指向与该键关联的值. 内部实现 Map是基于 散列表 ...
- .NET Core下的开源分布式任务调度系统ScheduleMaster-v2.0低调发布
从1月份首次公开介绍这个项目到现在也快4个月了,期间做了一些修修补补整体没什么大的改动.2.0算是发布之后第一个大的版本更新,带来了许多新功能新特性,也修复了一些已知的bug,在此感谢在博客.Issu ...
- jeecg ant design vue 一些收藏
1关于 进来清除上次记录 找到src/permission.js下的
- PG TO Oracle 增量同步-外部表
背景 最近在负责公司数据Oracle转PG:老平台数据库:Oracle11g:新平台数据库:PostgreSQL12.由于平台统计规则有变动:所以正在推广的游戏数据无法全部迁移过来:只能在老平台上运行 ...
- C语言字符数组超细讲解
看到标题,有不少朋友会想:字符数组不也是数组吗?为什么要单独拿出来讲哩?莫非它是朵奇葩? 哈哈,确实,一起来认识一下这朵数组界的奇葩吧! 一.字符数组的定义.引用.初始化 大家好!我是字符数组,看我的 ...
- udp协议与tcp协议
TCP协议与UDP协议支持的应用协议 TCP支持的应用协议主要有:Telnet.FTP.SMTP等: UDP支持的应用层协议主要有:NFS(网络文件系统).SNMP(简单网络管理协议).DNS(主域名 ...
- [Batch脚本] if else 的格式
必须写成一行 ) else (,否则报错. if %abc%=="yes" ( ... ) else ( ... )
- Spring Boot中使用Swagger CodeGen生成REST client
文章目录 什么是Open API规范定义文件呢? 生成Rest Client 在Spring Boot中使用 API Client 配置 使用Maven plugin 在线生成API Spring B ...