文章目录
- ② 将工作项添加到队列(源头queue_work_on)
沉淀、分享、成长,让自己和他人都能有所收获!😄
学习原因

共享工作队列是全局共享的,任务执行会相互影响,对于有特殊需求的驱动(如需要高优先级、独立调度的任务),需要创建自定义工作队列。
学习目的
- 掌握自定义工作队列的创建与使用方法,能为驱动创建独立的工作队列。
- 理解自定义工作队列的调度机制与优先级设置,避免任务被其他驱动阻塞。
- 理解自定义工作队列与共享工作队列的区别,能根据场景选择合适的工作队列。
学习内容
- 自定义工作队列的创建:create_workqueue()/alloc_workqueue(),设置队列名称、标志、CPU 亲和性。
- 自定义工作队列的 API:queue_work()、destroy_workqueue()。
- workqueue_struct结构体解析:内核工作队列的核心结构体,包含工作线程、任务链表等信息。
- 自定义工作队列的调度:任务会被提交到专属的内核线程执行,不会被其他驱动的任务阻塞。
- 自定义工作队列的优缺点:优点是独立调度、优先级可控;缺点是会创建额外的内核线程,占用系统资源。
一、工作队列的选择
共享队列是操作系统内核统一管理的公共任务池,所有程序都可以使用这个共用的队列来处理任务。而自定义队列则是由操作系统或设备驱动专门创建的独立任务池,用来执行特定的定制化操作。

简单来说:
- 自定义队列:专门定制的任务通道,为特定功能服务
两者的主要区别在于:共享队列是系统级通用工具,自定义队列是针对具体需求设计的专用工具。
二、自定义工作队列介绍
2.1、工作队列相关结构体
① work_struct工作项:
在 Linux 内核中,结构体 struct work_struct 描述的是要延迟执行的工作项,定义在include/linux/workqueue.h 当中,如下所示:
struct work_struct{
atomic_long_t data;
struct list_head entry;
work_func_t func;
#ifdefCONFIG_LOCKDEP
structlockdep_map lockdep_map;
#endif
};
主要成员:
- atomic_long_t data:存储工作项数据的字段,支持安全的多线程访问
- struct list_head entry:工作项在队列中的链表节点,用于将工作项连接到队列中
- work_func_t func:工作项执行时调用的处理函数
② workqueue_struct 工作队列
这些工作组织成工作队列,内核使用 struct workqueue_struct 结构体描述一个工作队列,定义在 kernel/workqueue.c 当中,如下所示:
/*
* The externally visible workqueue. It relays the issued work items to
* the appropriate worker_pool through its pool_workqueues.
*/
struct workqueue_struct{
struct list_head pwqs;/* WR: all pwqs of this wq */
struct list_head list;/* PR: list of all workqueues */
struct mutex mutex;/* protects this wq */
int work_color;/* WQ: current work color */
int flush_color;/* WQ: current flush color */
atomic_t nr_pwqs_to_flush;/* flush in progress */
struct wq_flusher*first_flusher;/* WQ: first flusher */
struct list_head flusher_queue;/* WQ: flush waiters */
struct list_head flusher_overflow;/* WQ: flush overflow list */
struct list_head maydays;/* MD: pwqs requesting rescue */
struct worker*rescuer;/* I: rescue worker */
int nr_drainers;/* WQ: drain in progress */
int saved_max_active;/* WQ: saved pwq max_active */
struct workqueue_attrs*unbound_attrs;/* PW: only for unbound wqs */
struct pool_workqueue*dfl_pwq;/* PW: only for unbound wqs */
#ifdef CONFIG_SYSFS
struct wq_device*wq_dev;/* I: for sysfs interface */
#endif
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
char name[WQ_NAME_LEN];/* I: workqueue name */
/*
* Destruction of workqueue_struct is sched-RCU protected to allow
* walking the workqueues list without grabbing wq_pool_mutex.
* This is used to dump all workqueues from sysrq.
*/
struct rcu_head rcu;
/* hot fields used during command issue, aligned to cacheline */
unsignedint flags ____cacheline_aligned;/* WQ: WQ_* flags */
struct pool_workqueue __percpu *cpu_pwqs;/* I: per-cpu pwqs */
struct pool_workqueue __rcu *numa_pwq_tbl[];/* PWR: unbound pwqs indexed by node */
};
2.2、工作队列相关接口函数
include/linux/workqueue.h ----- API 声明位置
2.2.1、关键API:创建与添加
① 创建工作队列
create_workqueue(name)
- 作用:创建一个工作队列,每个CPU都会对应一个独立的线程。
create_singlethread_workqueue(name)
- 作用:创建一个仅单线程的工作队列,不管有多少CPU,只创建一个线程。
② 将工作项添加到队列(源头queue_work_on)
我们经常用的是queue_work。其实底层都是调用queue_work_on
tatic inline bool queue_work(structworkqueue_struct*wq,
structwork_struct*work)
{
returnqueue_work_on(WORK_CPU_UNBOUND, wq, work);
}
queue_work_on(cpu, wq, work)
- 作用:把一个工作项立即放入指定CPU的队列,等待执行。
2.2.2、关键API:取消与清理
① 取消已调度的工作
cancel_work_sync(work)
② 强制处理队列中的所有工作
flush_workqueue(wq)
- 作用:立即执行队列中所有未完成的工作,直到全部处理完毕。
③ 删除工作队列
destroy_workqueue(wq)
- 前提:必须确保队列中的所有工作已执行完毕(可通过flush_workqueue完成)。
④ 使用流程总结
- 创建队列:用create_workqueue或create_singlethread_workqueue。
- 添加工作:用queue_work_on将工作项放入队列。
- 取消工作:用cancel_work_sync终止未执行的工作。
- 清理队列:用flush_workqueue确保所有工作完成,再用destroy_workqueue删除队列。
三、自定义共享队列案例
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
int irq;
struct workqueue_struct*test_workqueue;
struct work_struct test_workqueue_work;
// 工作项处理函数
void test_work(structwork_struct*work)
{
msleep(1000);
printk("This is test_work\n");
}
// 中断处理函数
irqreturn_ttest_interrupt(int irq,void*args)
{
printk("This is test_interrupt\n");
//schedule_work(&test_workqueue);
//提交一个任务 给 工作队列
//worker ---- 调度者
queue_work(test_workqueue,&test_workqueue_work);// 提交工作项到工作队列
returnIRQ_RETVAL(IRQ_HANDLED);
}
staticintinterrupt_irq_init(void)
{
int ret;
irq =gpio_to_irq(104);// 将GPIO映射为中断号
printk("irq is %d\n", irq);
// 请求中断
ret =request_irq(irq, test_interrupt, IRQF_TRIGGER_RISING,"test",NULL);
if(ret <0)
{
printk("request_irq is error\n");
return-1;
}
//test_workqueue ---- workqueue_struct
//test_workqueue_work --- work_struct
//test_work --- 函数
test_workqueue_work=create_workqueue("test_workqueue");// 创建工作队列(比共享工作队列多的一行)
INIT_WORK(&test_workqueue_work, test_work);// 初始化工作项
return0;
}
staticvoidinterrupt_irq_exit(void)
{
free_irq(irq,NULL);// 释放中断
cancel_work_sync(&test_workqueue_work);// 取消工作项
flush_workqueue(test_workqueue);// 刷新工作队列
destroy_workqueue(test_workqueue);// 销毁工作队列
printk("bye bye\n");
}
module_init(interrupt_irq_init);
module_exit(interrupt_irq_exit);
MODULE_LICENSE("GPL");