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_LOCKDEPstruct 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 secondsprintk(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 学习总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java中的IO整理
- 下一篇: 红帽linux安装要钱吗,红帽linux