工作队列
工作队列(work queue)是使用内核线程异步执行函数的通用机制。
工作队列是中断处理程序的一种下半部机制,中断处理程序可以把耗时比较长并且可能睡眠的函数交给工作队列。
工作队列不完全是中断处理程序的下半部,同时内核的其他模块也可以将异步执行的函数交给它执行。
1. 编程接口
内核使用工作项保存需要异步执行的函数,工作项的数据接口是work_struct,其定义如下:
include/linux/workqueue.h
struct work_struct {
atomic_long_t data;
struct list_head entry;
work_func_t func; /* 异步执行的函数 */
};
typedef void (*work_func_t)(struct work_struct *work); /* 异步执行的函数原型 */
有一类工作项称为延迟工作项,其数据类型为delayed_work,定义如下:
include/linux/workqueue.h
struct delayed_work {
struct work_struct work; /* 工作项 */
struct timer_list timer; /* 定时器 */
/* target workqueue and CPU ->timer uses to queue ->work */
struct workqueue_struct *wq;
int cpu;
};
把延迟工作项添加到工作队列中的时候,延迟一段时间才会真正地把工作项添加到工作队列中。
工作队列分为两种,一种是内核定义的,一种是自己创建的。内核定义的工作队列如下:
include/linux/workqueue.h
extern struct workqueue_struct *system_wq; /* 如果工作项的执行时间比较短,应该使用这个工作队列 */
extern struct workqueue_struct *system_highpri_wq; /* 高优先级的工作队列 */
extern struct workqueue_struct *system_long_wq; /* 如果工作队列的执行时间比较长,应该使用这个工作队列 */
extern struct workqueue_struct *system_unbound_wq; /* 这个工作队列使用的内核线程不绑定到某个特定的处理器 */
extern struct workqueue_struct *system_freezable_wq; /* 这个工作队列可以冻结 */
extern struct workqueue_struct *system_power_efficient_wq; /* 如果开启了工作队列模块的参数“wq_power_efficient”,那么这个工作队列倾向于省电,否则根system_wq相同 */
extern struct workqueue_struct *system_freezable_power_efficient_wq; /* 这个工作队列和system_power_efficient_wq的区别是可以冻结 */
(1)定义工作项
定义一个静态的工组项:
DECLARE_WORK(n, f) /* 参数n是变量名称,参数f是工作项的处理函数 */
定义一个静态的延迟工作项:
DECLARE_DELAYED_WORK(n, f) /* 参数n是变量名称,参数f是工作项的处理函数 */
定义一个静态的延迟工作项,但使用可推迟的定时器(deferrable timer):
DECLARE_DEFERRABLE_WORK(n, f) /* 参数n是变量名称,参数f是工作项的处理函数 */
动态初始化一个工作项:
INIT_WORK(_work, _func) /* 参数_work是工作项地址,参数_func是需要异步执行的函数 */
动态初始化一个工作项,工作项是栈里面的局部变量:
INIT_WORK_ONSTACK(_work, _func) /* 参数_work是工作项地址,参数_func是需要异步执行的函数 */
动态初始化一个延迟工作项:
INIT_DELAYED_WORK(_work, _func)
动态初始化一个延迟工作项,工作项是栈里面的局部变量:
INIT_DELAYED_WORK_ONSTACK(_work, _func)
动态初始化一个延迟工作项,但使用可推迟的定时器:
INIT_DEFERRABLE_WORK(_work, _func)
动态初始化一个延迟工作项,工作项是栈里面的局部变量,但使用可推迟的定时器:
INIT_DEFERRABLE_WORK_ONSTACK(_work, _func)
(2)全局工作队列
在全局工作队列中添加一个工作项:
bool schedule_work(struct work_struct *work);
在全局工作队列中添加一个工作项,并且指定工作项的处理器:
bool schedule_work_on(int cpu, struct work_struct *work);
在全局工作队列中添加一个延迟工作项:
bool schedule_delayed_work(struct delayed_work *dwork,
unsigned long delay) /* 参数delay是把工作项添加到工作队列中之前等待的时间,单位是嘀嗒(tick) */
在全局工作队列中添加一个延迟工作项,并且指定工作项的处理器:
bool schedule_delayed_work_on(int cpu, struct delayed_work *dwork,
unsigned long delay) /* 参数delay是把工作项添加到工作队列中之前等待的时间,单位是嘀嗒(tick) */
冲刷全局工作队列,确保全局工作队列中的所有工作项执行完:
bool flush_work(struct work_struct *work);
(3)专用工作队列
分配工作队列:
/* 参数fmt是工作队列名称的格式 */
/* 参数flag是标志位,可以是0,也可以是下面这些标志位的组合 */
enum {
WQ_UNBOUND = 1 << 1, /* 处理工作项的内核线程不绑定到任何特定的处理器 */
WQ_FREEZABLE = 1 << 2, /* 在系统挂起的时候冻结 */
WQ_MEM_RECLAIM = 1 << 3, /* 在内存回收的时候可能使用这个工作队列 */
WQ_HIGHPRI = 1 << 4, /* 高优先级 */
WQ_CPU_INTENSIVE = 1 << 5, /* 处理器密集型 */
WQ_SYSFS = 1 << 6,
WQ_POWER_EFFICIENT = 1 << 7, /* 省电 */
__WQ_DRAINING = 1 << 16,
__WQ_ORDERED = 1 << 17,
__WQ_LEGACY = 1 << 18,
__WQ_ORDERED_EXPLICIT = 1 << 19,
WQ_MAX_ACTIVE = 512,
WQ_MAX_UNBOUND_PER_CPU = 4,
WQ_DFL_ACTIVE = WQ_MAX_ACTIVE / 2,
};
/* 参数max_active是每个处理器可以同时执行的工作项的最大数量,0表示使用默认值 */
/* 参数args是传给参数fmt的参数 */
alloc_workqueue(fmt, flags, max_active, args...)
分配一个有序的工作队列,有序的工作队列在任何时刻,按照入队的顺序只执行一个工作项:
alloc_ordered_workqueue(fmt, flags, args...)
在指定的工作队列中添加一个工作项:
bool queue_work(struct workqueue_struct *wq, struct work_struct *work);
在指定的工作队列中添加一个工作项,并且指定执行工作项的处理器:
bool queue_work_on(int cpu, struct workqueue_struct *wq, struct work_struct *work);
冲刷工作队列,确保工作队列中的所有工作项执行完:<

本文详细解析了Linux工作队列(workqueue)的原理与编程接口,介绍如何使用内核线程异步执行函数,包括工作项、延迟工作项、全局与专用工作队列的管理,以及工人处理工作和工人池动态管理机制。
最低0.47元/天 解锁文章
875

被折叠的 条评论
为什么被折叠?



