Linux自從2.6.20之後,工作隊列發生了一些變化,目前從網絡上搜索的資料一般都是介紹老版本的工作隊列,很少見到對新版本的介紹。本文對新老版本都做了簡要概述,並分別提供了簡單的實作案例。
工作隊列(work queue)是Linux kernel中將工作推後執行的一種機制。這種機制和BH或Tasklets不同之處在於工作隊列是把推後的工作交由一個內核線程去執行,因此工作隊列的優勢就在於它允許重新調度甚至睡眠。
工作隊列是2.6內核開始引入的機制,在2.6.20之後,工作隊列的數據結構發生了一些變化,因此本文分成兩個部分對2.6.20之前和之後的版本分別做介紹。
1、2.6.0~2.6.19
數據結構:
struct work_struct {
unsigned long pending;
struct list_head entry;
void (*func)(void *);
void *data;
void *wq_data;
struct timer_list timer;
};
pending是用來記錄工作是否已經掛在隊列上;
entry是循環鏈表結構;
func作為函數指針,由用戶實現;
data用來存儲用戶的私人數據,此數據即是func的參數;
wq_data一般用來指向工作者線程(工作者線程參考下文);
timer是推後執行的定時器。
work_struct的這些變量裡,func和data是用戶使用的,其他是內部變量,我們可以不用太過關心。
API:
1) INIT_WORK(_work, _func, _data)
初始化指定工作,目的是把用戶指定的函數_func及_func需要的參數_data賦給work_struct的func及data變量。
2) int schedule_work(struct work_struct *work)
對工作進行調度,即把給定工作的處理函數提交給缺省 的工作隊列和工作者線程。工作者線程本質上是一個普通的內核線程,在默認情況下,每個CPU均有一個類型為“events”的工作者線程,當調用 schedule_work時,這個工作者線程會被喚醒去執行工作鏈表上的所有工作。
3) int schedule_delayed_work(struct work_struct *work, unsigned long delay)
延遲執行工作,與schedule_work類似。
4) void flush_scheduled_work(void)
刷新缺省工作隊列。此函數會一直等待,直到隊列中的所有工作都被執行。
5) int cancel_delayed_work(struct work_struct *work)
flush_scheduled_work並不取消任何延遲執行的工作,因此,如果要取消延遲工作,應該調用cancel_delayed_work。
以上均是采用缺省工作者線程來實現工作隊列,其優點是簡單易用,缺點是如果缺省工作隊列負載太重,執行效率會很低,這就需要我們創建自己的工作者線程和工作隊列。
API:
1) struct workqueue_struct *create_workqueue(const char *name)
創建新的工作隊列和相應的工作者線程,name用於該內核線程的命名。
2) int queue_work(struct workqueue_struct *wq, struct work_struct *work)
類似於schedule_work,區別在於queue_work把給定工作提交給創建的工作隊列wq而不是缺省隊列。
3) int queue_delayed_work(struct workqueue_struct *wq, struct work_struct *work, unsigned long delay)
延遲執行工作。
4) void flush_workqueue(struct workqueue_struct *wq)
刷新指定工作隊列。
5) void destroy_workqueue(struct workqueue_struct *wq)