Wednesday, January 04, 2012

Linux中Workqueue機制分析

資料來源: Linux中Workqueue機制分析


Linux中Workqueue機制分析

    走入Linux的殿堂已經有一年有餘了,在這裡我想將Linux的各種實現機制分析一遍,一方面對自己來說也是溫故而知新,另一方面,促進大家的交流,最好能夠給大家一些拋磚引玉的啟迪。我是硬件出身,搞硬件已經好多年了,從是專門軟件開發也接近兩年了,在這一段時間內我越發認為軟硬件協同設計是未來發展的主流,軟硬件的界限越來越模糊,軟硬件的設計思想是相通的,實現方法是各異的,實現的結果上當然也存在較大差別,因此,很有必要做好軟硬件的協同設計。本著這樣的想法,我想將我所認識的Linux分析一遍,特別是一些我認為精華和重要的機制,另外在討論過程中,我會插入一些其他的OS實現機制,進行對比分析,我把這一類blog文章劃歸為「Linux機制分析」,希望大家支持。

什麼是workqueue

Linux中的Workqueue機制就是為了簡化內核線程的創建。通過調用workqueue的接口就能創建內核線程。並且可以根據當前系統CPU的個數創建線程的數量,使得線程處理的事務能夠並行化。
workqueue是內核中實現簡單而有效的機制,他顯然簡化了內核daemon的創建,方便了用戶的編程,

Workqueue機制的實現

Workqueue機制中定義了兩個重要的數據結構,分析如下:
1、          cpu_workqueue_struct結構。該結構將CPU和內核線程進行了綁定。在創建workqueue的過程中,Linux根據當前系統CPU的個數創建cpu_workqueue_struct。在該結構主要維護了一個任務隊列,以及內核線程需要睡眠的等待隊列,另外還維護了一個任務上下文,即task_struct
2、          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_workqueueworkqueue隊列進行初始化時,內核就開始為用戶分配一個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都創建一個內核線程。輸入參數:
@nameworkqueue的名稱
2
create_singlethread_workqueue
用於創建workqueue,只創建一個內核線程。輸入參數:
@nameworkqueue名稱
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

No comments: