工作隊列(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-;
}
static void __exit test_exit(void)
{
destroy_workqueue(queue);
}
MODULE_LICENSE("GPL");
module_init(test_init);
module_exit(test_exit);