天天看點

Linux中等待隊列的實作

   在軟體開發中任務經常由于某種條件沒有得到滿足而不得不進入睡眠狀态,然後等待條件得到滿足的時候再繼續運作,進入運作狀态。這種需求需要等待隊列機制的支援。Linux中提供了等待隊列的機制,該機制在核心中應用很廣泛。

       在Linux核心中使用等待隊列的過程很簡單,首先定義一個wait_queue_head,然後如果一個task想等待某種事件,那麼調用wait_event(等待隊列,事件)就可以了。

     等待隊列應用廣泛,但是核心實作卻十分簡單。其涉及到兩個比較重要的資料結構:__wait_queue_head,該結構描述了等待隊列的鍊頭,其包含一個連結清單和一個原子鎖,結構定義如下:

struct __wait_queue_head {

      spinlock_t lock;                    /* 保護等待隊列的原子鎖 */

      struct list_head task_list;          /* 等待隊列 */

};

__wait_queue,該結構是對一個等待任務的抽象。每個等待任務都會抽象成一個wait_queue,并且挂載到wait_queue_head上。該結構定義如下:

struct __wait_queue {

 unsigned int flags;

 void *private;                       /* 通常指向目前任務控制塊 */

/* 任務喚醒操作方法,該方法在核心中提供,通常為autoremove_wake_function */

 wait_queue_func_t func;             

 struct list_head task_list;              /* 挂入wait_queue_head的挂載點 */

        Linux中等待隊列的實作思想如下圖所示,當一個任務需要在某個wait_queue_head上睡眠時,将自己的程序控制塊資訊封裝到wait_queue中,然後挂載到wait_queue的連結清單中,執行排程睡眠。當某些事件發生後,另一個任務(程序)會喚醒wait_queue_head上的某個或者所有任務,喚醒工作也就是将等待隊列中的任務設定為可排程的狀态,并且從隊列中删除。

<a href="http://space.ednchina.com/Upload/Blog/2008/7/11/61ed3ba8-b428-42d0-adfc-89c427234a75.JPG" target="_blank"></a>

    使用等待隊列時首先需要定義一個wait_queue_head,這可以通過DECLARE_WAIT_QUEUE_HEAD宏來完成,這是靜态定義的方法。該宏會定義一個wait_queue_head,并且初始化結構中的鎖以及等待隊列。當然,動态初始化的方法也很簡單,初始化一下鎖及隊列就可以了。

       一個任務需要等待某一事件的發生時,通常調用wait_event,該函數會定義一個wait_queue,描述等待任務,并且用目前的程序描述塊初始化wait_queue,然後将wait_queue加入到wait_queue_head中。函數實作流程說明如下:

1、用目前的程序描述塊(PCB)初始化一個wait_queue描述的等待任務。

2、在等待隊列鎖資源的保護下,将等待任務加入等待隊列。

3、判斷等待條件是否滿足,如果滿足,那麼将等待任務從隊列中移出,退出函數。

4、 如果條件不滿足,那麼任務排程,将CPU資源交與其它任務。

5、 當睡眠任務被喚醒之後,需要重複(2)、(3)步驟,如果确認條件滿足,退出等待事件函數。

<b>等待隊列程式設計接口</b><b></b>

序号

程式設計接口

使用說明

1

wait_event

這是一個宏,讓目前任務處于等待事件狀态。輸入參數如下:

@wq:等待隊列

@conditions:等待條件

2

wait_event_timeout

功能與wait_event類似,多了一個逾時機制。參數中多了一項逾時時間。

3

wait_event_interruptible

這是一個宏,與前兩個宏相比,該宏定義的等待能夠被消息喚醒。如果被消息喚醒,那麼傳回- ERESTARTSYS。輸入參數如下:

@condition:等待條件

@rt:傳回值

4

wait_event_interruptible_timeout

與(3)相比,多了逾時機制

5

wake_up

喚醒等待隊列中的一個任務

6

wake_up_all

喚醒等待隊列中的所有任務

繼續閱讀