Linux内核工作队列
Linux中的Workqueue机制就是为了简化内核线程的创建。通过调用workqueue的接口就能创建内核线程。并且可以根据当前系统CPU的个数创建线程的数量,使得线程处理的事务能够并行化。workqueue是内核中实现简单而有效的机制,他显然简化了内核daemon的创建,方便了用户的编程.
工作队列(workqueue)是另外一种将工作推后执行的形式.工作队列可以把工作推后,交由一个内核线程去执行,也就是说,这个下半部分可以在进程上下文中执行。最重要的就是工作队列允许被重新调度甚至是睡眠。
1.工作队列和软中断/tasklet中作出选择
- 如果推后执行的任务需要睡眠,那么只能选择工作队列;
- 如果推后执行的任务需要延时指定的时间再触发,那么使用工作队列,因为其可以利用timer延时
- 如果推后执行的任务需要在一个tick之内处理,则使用软中断或tasklet,因为其可以抢占普通进程和内核线程
- 如果推后执行的任务对延迟的时间没有任何要求,则使用工作队列,此时通常为无关紧要的任务
实际上,工作队列的本质就是将工作交给内核线程处理,因此其可以用内核线程替换。但是内核线程的创建和销毁对编程者的要求较高,而工作队列实现了内核线程的封装,不易出错,所以我们也推荐使用工作队列。
2.数据结构
//工作队列
struct workqueue_struct {
struct list_head pwqs; /* WR: all pwqs of this wq */
struct list_head list; /* PL: 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; /* WQ: only for unbound wqs */
struct pool_workqueue *dfl_pwq; /* WQ: 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 */
/* hot fields used during command issue, aligned to cacheline */
unsigned int flags ____cacheline_aligned; /* WQ: WQ_* flags */
struct pool_workqueue __percpu *cpu_pwqs; /* I: per-cpu pwqs */
struct pool_workqueue __rcu *numa_pwq_tbl[]; /* FR: unbound pwqs indexed by node */
};
//工作任务
struct work_struct {
atomic_long_t data;
struct list_head entry;
work_func_t func;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
//延时任务
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;
};
3.创建与销毁workqueue_struct
//创建
#define alloc_ordered_workqueue(fmt, flags, args...) \
alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args)
//多处理器时会为每个cpu创建一个工作者线程
#define create_workqueue(name) \
alloc_workqueue((name), WQ_MEM_RECLAIM, 1)
//只创建一个工作者线程,系统挂起,线程也挂起
#define create_freezable_workqueue(name) \
alloc_workqueue((name), WQ_FREEZABLE | WQ_UNBOUND | WQ_MEM_RECLAIM, 1)
//单核还是多核,都只在其中一个CPU上创建线程
#define create_singlethread_workqueue(name) \
alloc_workqueue((name), WQ_UNBOUND | WQ_MEM_RECLAIM, 1)
//释放创建的工作列队资源
extern void destroy_workqueue(struct workqueue_struct *wq);
//保证workqueue上的work都处理完了
extern void flush_workqueue(struct workqueue_struct *wq);
4.初始化work_struct
//工作队列待执行函数原型
typedef void (*work_func_t)(struct work_struct *work);
/* 静态初始化 */
//定义初始化工作任务work_struct
DECLARE_WORK(n,f);
//定义初始化延时执行工作任务delayed_work
DECLARE_DELAYED_WORK(n,f);
//定义初始化延时执行工作任务delayed_work,如果处理器繁忙允许延后执行
DECLARE_DEFERRABLE_WORK(n, f)
/* 动态初始化 */
//初始化工作任务work_struct
INIT_WORK(_work, _func)
//初始化延时工作任务delayed_work
INIT_DELAYED_WORK(_work, _func)
//初始化延时执行工作任务delayed_work,如果处理器繁忙允许延后执行
INIT_DEFERRABLE_WORK(_work, _func)
INIT_DELAYED_WORK_ONSTACK(_work, _func)
INIT_DEFERRABLE_WORK_ONSTACK(_work, _func)
//修改_func
PREPARE_WORK(_work, _func)
//例如
void func(struct work_struct *work){}
void funca(struct work_struct *work){}
struct work_struct wo;
INIT_WORK(&wo,func);
PREPARE_WORK(&wo,funca);
5.调度work
//将工作加入工作列队进行调度
static inline bool queue_work(struct workqueue_struct *wq,struct work_struct *work)
//延时调用指定工作列队的工作
static inline bool queue_delayed_work(struct workqueue_struct *wq,struct delayed_work *dwork,unsigned long delay)
static inline bool mod_delayed_work(struct workqueue_struct *wq,struct delayed_work *dwork,unsigned long delay)
6.取消work
extern bool cancel_work_sync(struct work_struct *work);
extern bool cancel_delayed_work(struct delayed_work *dwork);
extern bool cancel_delayed_work_sync(struct delayed_work *dwork);
7.等待work完成
//等待工作完成返回true,工作已经完成返回false
extern bool flush_work(struct work_struct *work);
extern bool flush_delayed_work(struct delayed_work *dwork);
8.共享队列
共享队列,就是系统创建了默认的workqueue,只需要定义初始化work,调用接口就完成。
8.1 共享队列的调度
bool schedule_work(struct work_struct *work);
bool schedule_delayed_work(struct delayed_work *dwork,unsigned long delay);
8.2 取消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);
8.3 等待work完成
extern void flush_scheduled_work(void);
9.驱动实例
delayed_work和work_struct操作是一样的根据work_struct的demo举一反三
9.1 demo1(INIT_WORK)
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
#define err(msg) printk(KERN_ERR "%s: " msg "\n", DRIVER_NAME)
#define __debug(fmt, arg...) printk(KERN_INFO fmt, ##arg)
struct timer_list timer;
struct workqueue_struct *wq;
struct work_struct work;
void work_queue_fun(struct work_struct *work)
{
//mdelay(5000);
msleep(5000);
__debug("==========work_queue_fun==========\n");
}
void work_queue_timer(unsigned long arg)
{
__debug("==========work_queue_timer==========\n");
queue_work(wq ,&work);
}
static int __init work_queue_init(void)
{
init_timer(&timer);
timer.function = work_queue_timer;
add_timer(&timer);
mod_timer(&timer, jiffies + HZ * 3);
wq = create_workqueue("wq_test"); //初始化工作对列
INIT_WORK(&work, work_queue_fun); //初始化任务
__debug("\n===================work_queue_init====================\n");
return 0;
}
static void __exit work_queue_exit(void)
{
flush_work(&work); //刷新任务
flush_workqueue(wq); //刷新工作队列
destroy_workqueue(wq); //注销工作队列
del_timer(&timer);
__debug("\n===================work_queue_exit====================\n");
return;
}
module_init(work_queue_init);
module_exit(work_queue_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("wyy");
9.2 demo2(DECLARE_WORK)
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
#define err(msg) printk(KERN_ERR "%s: " msg "\n", DRIVER_NAME)
#define __debug(fmt, arg...) printk(KERN_INFO fmt, ##arg)
struct timer_list timer;
struct workqueue_struct *wq;
void work_queue_fun(struct work_struct *work)
{
//mdelay(5000);
msleep(5000);
__debug("==========work_queue_fun==========\n");
}
DECLARE_WORK(work,work_queue_fun);
void work_queue_timer(unsigned long arg)
{
__debug("==========work_queue_timer==========\n");
queue_work(wq ,&work);
}
static int __init work_queue_init(void)
{
init_timer(&timer);
timer.function = work_queue_timer;
add_timer(&timer);
mod_timer(&timer, jiffies + HZ * 3);
wq = create_workqueue("wq_test"); //初始化工作对列
__debug("\n===================work_queue_init====================\n");
return 0;
}
static void __exit work_queue_exit(void)
{
flush_work(&work); //刷新任务
flush_workqueue(wq); //刷新工作队列
destroy_workqueue(wq); //注销工作队列
del_timer(&timer);
__debug("\n===================work_queue_exit====================\n");
return;
}
module_init(work_queue_init);
module_exit(work_queue_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("wyy");
9.3 demo3(delay_work)
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
#define err(msg) printk(KERN_ERR "%s: " msg "\n", DRIVER_NAME)
#define __debug(fmt, arg...) printk(KERN_INFO fmt, ##arg)
struct timer_list timer;
struct workqueue_struct *wq;
struct delayed_work work;
void work_queue_fun(struct work_struct *work)
{
__debug("==========work_queue_fun==========\n");
}
void work_queue_timer(unsigned long arg)
{
__debug("==========work_queue_timer==========\n");
queue_delayed_work(wq ,&work,5 * HZ);
}
static int __init work_queue_init(void)
{
init_timer(&timer);
timer.function = work_queue_timer;
add_timer(&timer);
mod_timer(&timer, jiffies + HZ * 3);
wq = create_workqueue("wq_test"); //初始化工作对列
INIT_DELAYED_WORK(&work, work_queue_fun); //初始化任务
__debug("\n===================work_queue_init====================\n");
return 0;
}
static void __exit work_queue_exit(void)
{
flush_delayed_work(&work); //刷新任务
flush_workqueue(wq); //刷新工作队列
destroy_workqueue(wq); //注销工作队列
del_timer(&timer);
__debug("\n===================work_queue_exit====================\n");
return;
}
module_init(work_queue_init);
module_exit(work_queue_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("wyy");
9.4 demo4(共享队列)
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
#define err(msg) printk(KERN_ERR "%s: " msg "\n", DRIVER_NAME)
#define __debug(fmt, arg...) printk(KERN_INFO fmt, ##arg)
struct timer_list timer;
struct work_struct work;
void work_queue_fun(struct work_struct *work)
{
//mdelay(5000);
msleep(5000);
__debug("==========work_queue_fun==========\n");
}
void work_queue_timer(unsigned long arg)
{
__debug("==========work_queue_timer==========\n");
schedule_work(&work);
}
static int __init work_queue_init(void)
{
init_timer(&timer);
timer.function = work_queue_timer;
add_timer(&timer);
mod_timer(&timer, jiffies + HZ * 3);
INIT_WORK(&work, work_queue_fun); //初始化任务
__debug("\n===================work_queue_init====================\n");
return 0;
}
static void __exit work_queue_exit(void)
{
flush_work(&work); //刷新任务
cancel_work_sync(&work);
del_timer(&timer);
__debug("\n===================work_queue_exit====================\n");
return;
}
module_init(work_queue_init);
module_exit(work_queue_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("wyy");