標籤:
Workqueue機制中定義了兩個重要的資料結構,分析如下:
cpu_workqueue_struct結構。該結構將CPU和核心線程進行了綁定。在建立workqueue的過程中,Linux根據當前系統CPU的個數建立cpu_workqueue_struct。在該結構主要維護了一個任務隊列,以及核心線程需要睡眠的等待隊列,另外還維護了一個任務上下文,即task_struct。
work_struct結構是對任務的抽象。在該結構中需要維護具體的任務方法,需要處理的資料,以及任務處理的時間。該結構定義如下:
struct work_struct {
unsigned long pending;
struct list_head entry; /* 將任務掛載到queue的掛載點 */
void (*func)(void *); /* 任務方法 */
void *data; /*任務處理的資料*
void *wq_data; /*work的屬主 */
strut timer_list timer; /* 任務延時處理定時器 */
};
當使用者調用workqueue的初始化介面create_workqueue或者create_singlethread_workqueue對workqueue隊列進行初始化時,核心就開始為使用者指派一個workqueue對象,並且將其鏈到一個全域的workqueue隊列中。然後Linux根據當前CPU的情況,為workqueue對象分配與CPU個數相同的cpu_workqueue_struct對象,每個cpu_workqueue_struct對象都會存在一條任務隊列。緊接著,Linux為每個cpu_workqueue_struct對象分配一個核心thread,即核心daemon去處理每個隊列中的任務。至此,使用者調用初始化介面將workqueue初始化完畢,返回workqueue的指標。
在初始化workqueue過程中,核心需要初始化核心線程,註冊的核心線程工作比較簡單,就是不斷的掃描對應cpu_workqueue_struct中的任務隊列,從中擷取一個有效任務,然後執行該任務。所以如果任務隊列為空白,那麼核心daemon就在cpu_workqueue_struct中的等待隊列上睡眠,直到有人喚醒daemon去處理任務隊列。
Workqueue初始化完畢之後,將任務啟動並執行上下文環境構建起來了,但是具體還沒有可執行檔任務,所以,需要定義具體的work_struct對象。然後將work_struct加入到任務隊列中,Linux會喚醒daemon去處理任務。
上述描述的workqueue核心實現原理可以描述如下:
在Workqueue機制中,提供了一個系統預設的workqueue隊列——keventd_wq,這個隊列是Linux系統在初始化的時候就建立的。使用者可以直接初始化一個work_struct對象,然後在該隊列中進行調度,使用更加方便。
Workqueue編程介面
|
序號
|
介面函數
|
說明
|
|
1
|
create_workqueue
|
用於建立一個workqueue隊列,為系統中的每個CPU都建立一個核心線程。輸入參數:
@name:workqueue的名稱
|
|
2
|
create_singlethread_workqueue
|
用於建立workqueue,只建立一個核心線程。輸入參數:
@name:workqueue名稱
|
|
3
|
destroy_workqueue
|
釋放workqueue隊列。輸入參數:
@ workqueue_struct:需要釋放的workqueue隊列指標
|
|
4
|
schedule_work
|
調度執行一個具體的任務,執行的任務將會被掛入Linux系統提供的workqueue——keventd_wq輸入參數:
@ work_struct:具體任務對象指標
|
|
5
|
schedule_delayed_work
|
延遲一定時間去執行一個具體的任務,功能與schedule_work類似,多了一個延遲時間,輸入參數:
@work_struct:具體任務對象指標
@delay:延遲時間
|
|
6
|
queue_work
|
調度執行一個指定workqueue中的任務。輸入參數:
@ workqueue_struct:指定的workqueue指標
@work_struct:具體任務對象指標
|
|
7
|
queue_delayed_work
|
延遲調度執行一個指定workqueue中的任務,功能與queue_work類似,輸入參數多了一個delay。
|
work queue 的使用執行個體:
struct my_work_t {
char *name;
struct work_struct work; //作為自己資料結構的成員,然後用container_of獲得my_work_t的指標
};
void my_func(struct work_struct *work)
{
struct my_work_t *my_work = container_of (work, struct my_work_t, work);
printk(KERN_INFO “Hello world, my name is %s!/n”, my_work->name);
}
struct workqueue_struct *my_wq = create_workqueue(“my wq”); //建立自己的work queue
struct my_work_t my_work;
my_work.name = “Jack”;
INIT_WORK(&(my_work.work), my_func); //初始化自己的work queue
queue_work(my_wq, &(my_work.work));
destroy_workqueue(my_wq); //銷毀自己的work queue
Workqueue機制的實現