工作队列(work queue)是Linux kernel中将工作推后执行的一种机制。这种机制和BH或Tasklets不同之处在于工作队列是把推后的工作交由一个内核线程去执行,因此工作队列的优势就在于它允许重新调度甚至睡眠。
每个工作队列有一个专门的线程,所有来自运行队列的任 务在进程的上下文中运行(这样它们可以休眠)。驱动程序可以创建并使用它们自己的工作队列,或者使用内核的一个工作队列。
工作队列的数据结构:
work_struct
结构体:
struct work_struct {
atomic_long_t data; //用来存储用户的私人数据,此数据即是func的参数
struct list_head entry; //循环链表结构;
work_func_t func; //函数指针,由用户实现;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
delayed_work结构体:
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;
};
初始化指定工作,目的是把用户指定的函数_func
#define INIT_WORK(_work, _func) \
__INIT_WORK((_work), (_func), 0)
#define INIT_DELAYED_WORK(_work, _func) \
__INIT_DELAYED_WORK(_work, _func, 0)
对工作进行调度,即把给定工作的处理函数提交给缺省的工作队列和工作者线程。工作者线程本质上是一个普通的内核线程,在默认情况下,每个CPU均有一个类型为“events”的工作者线程,当调用schedule_work时,这个工作者线程会被唤醒去执行工作链表上的所有工作。
static inline bool schedule_work(struct work_struct *work)
static inline bool schedule_delayed_work(struct delayed_work *dwork,
unsigned long delay)
刷新缺省工作队列。此函数会一直等待,直到队列中的所有工作都被执行。
static inline void flush_scheduled_work(void)
flush_scheduled_work
并不取消任何延迟执行的工作,因此,如果要取消延迟工作,应该调用cancel_delayed_work
。
bool cancel_delayed_work(struct delayed_work *dwork)
以上均是采用缺省工作者线程来实现工作队列,其优点是简单易用,缺点是如果缺省工作队列负载太重,执行效率会很低,这就需要我们创建自己的工作者线程和工作队列。
工作队列结构体:
/*
* 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 */
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[]; /* PWR: unbound pwqs indexed by node */
};
创建新的工作队列和相应的工作者线程,name用于该内核线程的命名。
#define create_workqueue(name) \
alloc_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM, 1, (name))
类似于schedule_work
,区别在于queue_work
把给定工作提交给创建的工作队列wq而不是缺省队列。
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)
刷新指定工作队列。
void flush_workqueue(struct workqueue_struct *wq)
示例:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/workqueue.h>
static struct workqueue_struct *queue=NULL;
static struct work_struct work;
staticvoid work_handler(struct work_struct *data)
{
printk(KERN_ALERT"work handler function.\n");
}
static int __init test_init(void)
{
queue=create_singlethread_workqueue("hello world");/*创建一个单线程的工作队列*/
if (!queue)
goto err;
INIT_WORK(&work,work_handler);
schedule_work(&work);
return0;
err:
return-1;
}
static void __exit test_exit(void)
{
destroy_workqueue(queue);
}
MODULE_LICENSE("GPL");
module_init(test_init);
module_exit(test_exit);