工作队列( work queue)是使用内核线程异步执行函数的通用机制。
工作队列是中断处理程序的一种下半部机制,中断处理程序可以把耗时比较长并且可能睡眠的函数交给工作队列执行。
工作队列不完全是中断处理程序的下半部。内核的很多模块需要异步执行函数,这些模块可以创建一个内核线程来异步执行函数。但是,如果每个模块都创建自己的内核线程,会造成内核线程的数量过多,内存消耗比较大,影响系统性能。所以,最好的方法是提供一种通用机制,让这些模块把需要异步执行的函数交给工作队列执行,共享内核线程,节省资源。
所以 Workqueue 的主要设计思想:一个是并行,多个 work 不要相互阻塞;另外一个是节省资源,多个 work 尽量共享资源 ( 进程、调度、内存 ),不要造成系统过多的资源浪费。
为了实现的设计思想,workqueue 的设计实现也更新了很多版本。最新的 workqueue 实现叫做 CMWQ(Concurrency Managed Workqueue)并发可管理工作队列,也就是用更加智能的算法来实现“并行和节省”。新版本的 workqueue 创建函数改成 alloc_workqueue(),旧版本的函数 create_workqueue() 逐渐会被被废弃。
内核使用工作项保存需要异步执行的函数,工作项的数据类型是 work_struct,需要异步执行的函数的原型如下所示:
struct work_struct {
atomic_long_t data;
struct list_head entry;
work_func_t func;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
typedef void(*work_func_t)(struct work_struct *work)
有一类工作项称为延迟工作项,数据类型是 delayed_work。把延迟工作项添加到工作队列中的时候,延迟一段时间才会真正地把工作项添加到工作队列中。延迟工作项是工作项和定时器的结合,可以避免使用者自己创建定时器。
我们可以使用内核定义的工作队列,也可以自己创建专用的工作队列。内核定义了以下工作队列:
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;
extern struct workqueue_struct *system_freezable_power_efficient_wq;
kernel/workqueue.c
int __init workqueue_init_early(void)
{
……
system_wq = alloc_workqueue(“events“, 0, 0);
system_highpri_wq = alloc_workqueue(“events_highpri”, WQ_HIGHPRI, 0);
system_long_wq = alloc_workqueue(“events_long“, 0, 0);
system_unbound_wq = alloc_workqueue(“events_unbound”, WQ_UNBOUND,
WQ_UNBOUND_MAX_ACTIVE);
system_freezable_wq = alloc_workqueue(“events_freezable“,
WQ_FREEZABLE, 0);
system_power_efficient_wq = alloc_workqueue(“events_power_efficient”,
WQ_POWER_EFFICIENT, 0);
system_freezable_power_efficient_wq = alloc_workqueue(“events_freezable_power_efficient”,
WQ_FREEZABLE | WQ_POWER_EFFICIENT,
0);
BUG_ON(!system_wq || !system_highpri_wq || !system_long_wq ||
!system_unbound_wq || !system_freezable_wq ||
!system_power_efficient_wq ||
!system_freezable_power_efficient_wq);
return 0;
}
system_wq:如果工作项的执行时间比较短,应该使用这个工作队列。早期的内核版本只提供了这个工作队列, 称为全局工作队列, 函数 schedule_work()和 schedule_delayed_work()使用这个工作队列。
system_highpri_wq:高优先级的工作队列。
system_long_wq:如果工作项的执行时间比较长,应该使用这个工作队列。
system_unbound_wq:这个工作队列使用的内核线程不绑定到某个特定的处理器。
system_freezable_wq:这个工作队列可以冻结。
system_power_efficient_wq:如果开启了工作队列模块的参数“ wq_power_efficient”,那么这个工作队列倾向于省电;否则和 system_wq 相同。
system_freezable_power_efficient_wq:这个工作队列和 system_power_efficient_wq 的区别是可以冻结。
(1)定义工作项。
定义一个静态的工作项,参数 n 是变量名称,参数 f 是工作项的处理函数。
DECLARE_WORK(n, f)
定义一个静态的延迟工作项,参数 n 是变量名称,参数 f 是工作项的处理函数。
DECLARE_DELAYED_WORK(n, f)
使用 DECLARE_DEFERRABLE_WORK(n, f)也可以定义一个静态的延迟工作项,和DECLARE_DELAYED_WORK()的区别是它使用可推迟的定时器( deferrable timer)。
可推迟的定时器在系统忙的时候工作正常,但是在处理器空闲的时候不会处理可推迟的定时器。当一个不可推迟的定时器唤醒处理器的时候,才会处理可推迟的定时器。
在运行时动态初始化工作项,方法如下。
1) INIT_WORK(_work, _func):初始化一个工作项,参数_work 是工作项的地址,参数_func 是需要异步执行的函数。
2) INIT_WORK_ONSTACK(_work, _func):初始化一个工作项,工作项是栈里面的局部变量,参数_work 是工作项的地址,参数_func 是需要异步执行的函数。
3) INIT_DELAYED_WORK(_work, _func):初始化一个延迟工作项,参数_work 是延迟工作项的地址,参数_func 是需要异步执行的函数。
4) INIT_DELAYED_WORK_ONSTACK(_work, _func):初始化一个延迟工作项,延迟工作项是栈里面的局部变量,参数_work 是延迟工作项的地址,参数_func 是需要异步执行的函数。
5) INIT_DEFERRABLE_WORK(_work, _func):初始化一个延迟工作项,和 INIT_DELAYED_WORK()的区别是它使用可推迟的定时器。
6) INIT_DEFERRABLE_WORK_ONSTACK(_work, _func):初始化一个延迟工作项,延迟工作项是栈里面的局部变量,和 INIT_DELAYED_WORK_ONSTACK()的区别是它使用可推迟的定时器。
(2)全局工作队列。
在全局工作队列中添加一个工作项。
bool schedule_work(struct work_struct *work);
在全局工作队列中添加一个工作项,并且指定执行工作项的处理器。
bool schedule_work_on(int cpu, struct work_struct *work);
在全局工作队列中添加一个延迟工作项,参数 delay 是把工作项添加到工作队列中之前等待的时间,单位是嘀嗒( tick)。
bool schedule_delayed_work(struct delayed_work *dwork, unsigned long delay);
在全局工作队列中添加一个延迟工作项,并且指定执行工作项的处理器。
bool schedule_delayed_work_on(int cpu, struct delayed_work *dwork,unsigned long delay);
冲刷全局工作队列,确保全局工作队列中的所有工作项执行完。
void flush_scheduled_work(void);
(3)专用工作队列。
分配工作队列的函数是:
alloc_workqueue(fmt, flags, max_active, args…)
1)参数 fmt 是工作队列名称的格式。
2)参数 flags 是标志位,可以是 0,也可以是下面这些标志位的组合。
WQ_UNBOUND:处理工作项的内核线程不绑定到任何特定的处理器。
WQ_FREEZABLE:在系统挂起的时候冻结。
WQ_MEM_RECLAIM:在内存回收的时候可能使用这个工作队列。
WQ_HIGHPRI:高优先级。
WQ_CPU_INTENSIVE:处理器密集型。
WQ_POWER_EFFICIENT:省电。
3)参数 max_active 是每个处理器可以同时执行的工作项的最大数量, 0 表示使用默认值256。
4)参数 args 是传给参数 fmt 的参数。
下面的函数用来分配一个有序的工作队列。有序的工作队列在任何时刻,按照入队的顺序只执行一个工作项。
alloc_ordered_workqueue(fmt, flags, args…)
#define alloc_ordered_workqueue(fmt, flags, args…)
alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED |
__WQ_ORDERED_EXPLICIT | (flags), 1, ##args)
兼容旧旧接口
#define create_workqueue(name)
alloc_workqueue(“%s”, __WQ_LEGACY | WQ_MEM_RECLAIM, 1, (name))
#define create_freezable_workqueue(name)
alloc_workqueue(“%s”, __WQ_LEGACY | WQ_FREEZABLE | WQ_UNBOUND |
WQ_MEM_RECLAIM, 1, (name))
#define create_singlethread_workqueue(name)
alloc_ordered_workqueue(“%s”, __WQ_LEGACY | WQ_MEM_RECLAIM, name)
在指定的工作队列中添加一个工作项。
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);
在指定的工作队列中添加一个延迟工作项,参数 delay 是把工作项添加到工作队列中之前等待的时间,单位是嘀嗒( tick)。
bool queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *dwork, unsigned long delay);
在指定的工作队列中添加一个延迟工作项,并且指定执行工作项的处理器。
bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq,struct delayed_work *work, unsigned long delay);
冲刷工作队列,确保工作队列中的所有工作项执行完。
void flush_workqueue(struct workqueue_struct *wq);
销毁工作队列的函数是:
void destroy_workqueue(struct workqueue_struct *wq);
(4)其他编程接口。
取消一个工作项。
bool cancel_work(struct work_struct *work);
取消一个工作项,并且等待取消操作执行完。
bool cancel_work_sync(struct work_struct *work);
取消一个延迟工作项。
bool cancel_delayed_work(struct delayed_work *dwork);
取消一个延迟工作项,并且等待取消操作执行完。
bool cancel_delayed_work_sync(struct delayed_work *dwork);
等待一个工作项执行完。
bool flush_work(struct work_struct *work);
等待一个延迟工作项执行完。
bool flush_delayed_work(struct delayed_work *dwork);
判断任务项目是否在进行中
bool work_pending(struct work_struct work );/*返回值为真表示正在运行,假表示停止*/
原文地址:https://blog.csdn.net/liu1250836704/article/details/134718905
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_35826.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!