蹉跎莫遣韶光老,人生唯有读书好。这篇文章主要讲述工作队列相关的知识,希望能为你提供帮助。
简介
工作队列就是内核中延后工作的一种方式,延后工作在无数场景都可以反复调度使用。
数据结构组成
/* @data: func的参数
* @entry: 连接工作的指针
* @func: 工作处理函数
*/struct work_struct {atomic_long_t data; struct list_head entry; work_func_t func; #ifdef CONFIG_LOCKDEPstruct lockdep_map lockdep_map; #endif};
使用流程
API 路径:kernel/kernel/workqueue.c; kernel/include/linux/workqueue.h
创建一个工作队列:
a. 创建一个服务于单个CPU的工作队列
/*@name:队列名 *RETURNS: Pointer to the allocated workqueue on success, %NULL on failure. */create_singlethread_workqueue(name);
b. 在每一个CPU上创建一个工作队列
/* @name:队列名 * RETURNS: Pointer to the allocated workqueue on success, %NULL on failure. */create_workqueue(name);
相对于create_singlethread_workqueue, create_workqueue同样会分配一个wq的工作队列,但是不同之处在于,对于多CPU系统而言,对每一个CPU,都会为之创建一个per-CPU的cwq结构,对应每一个cwq,都会生成一个新的worker_thread进程。但是当用queue_work向cwq上提交work节点时,是哪个CPU调用该函数,那么便向该CPU对应的cwq上的worklist上增加work节点。
初始化工作项
a. 动态注册
//kernel/include/linux/workqueue.hINIT_WORK(_work, _func)
【工作队列】b. 静态注册
//kernel/include/linux/workqueue.hDECLARE_WORK(_work, _func)
使用静态注册可以省略定义_work,且DECLARE_WORK需要放在代码头部预处理。
运行指定工作项
a. 自定义队列运行queue_work
/* @wq: workqueue to use * @work: work to queue * Returns %false if @work was already on a queue, %true otherwise. */queue_work(struct workqueue_struct *wq, struct work_struct *work)
b. 系统工作队列运行schedule_work
/* @work: 工作项 * Returns %false if @work was already on the kernel-global workqueue and %true otherwise. */schedule_work(struct work_struct *work)
queue_work,使用自定义队列运行工作项
schedule_work,调用系统的工作队列运行工作项。
小结:
一般情况下,需要指定情况多次重复调用工作项,选择定时器+queue_work。如果是指定情况下调用一次,则使用schedule_work,利用系统的工作队列执行需要的工作项。
使用流程
1.声明变量struct test_work_dev work_dev; static struct workqueue_struct *test1_workqueue = NULL;
2.声明回调函数void test1_callback(struct work_struct *work);
3.初始化队列项#if defined (DECLARE_WORK_SUPPORT )static DECLARE_WORK(test1_item, (void *) test1_callback); #endif
#if !defined(DECLARE_WORK_SUPPORT)static struct work_struct test1_item; test1_workqueue = create_singlethread_workqueue("test1_wq"); INIT_WORK(& test1_item, test1_callback); #endif
4.定义回调void test1_callback(struct work_struct *work) {printk("test1_callback!"); }
5.调度queue_work(test1_workqueue, & test1_item);
记录历经的路,分享个人总结与感悟。关注“开源519”,聊天窗口发送 “工作队列代码” 获取笔者本篇代码实例,更多驱动学习资料尽在“开源519”公众号。
推荐阅读
- 快乐就完事
- Iptables 使用
- 内核中的宏
- 函数指针的实例讲解(下)
- 并发与竞态(原子操作)
- IIC设备驱动实例调试
- Spark面试题——Spark资源调优
- #yyds干货盘点#一文读懂Hive底层数据存储格式
- C优先级