linux 等待隊列 第二篇

來源:互聯網
上載者:User

Linux核心的等待隊列是以雙迴圈鏈表為基礎資料結構,與進程調度機制緊密結合,能夠用於實現核心的非同步事件通知機制。

在這個鏈表中,有兩種資料結構:等待隊列頭(wait_queue_head_t)和等待隊列項(wait_queue_t)。等待隊列頭和等待隊列項中都包含一個list_head類型的域作為"串連件"。它通過一個雙鏈表和把等待tast的頭,和等待的進程列錶鏈接起來。從可以清晰看到。所以我們知道,如果要實現一個等待隊列,首先要有兩個部分。隊列頭和隊列項。下面看他們的資料結構。

[cpp]
view plaincopyprint?
  1. struct list_head { 
  2.     struct list_head *next, *prev; 
  3. }; 
  4. struct __wait_queue_head { 
  5.     spinlock_t lock; 
  6.     struct list_head task_list; 
  7. }; 
  8. typedef struct __wait_queue_head wait_queue_head_t; 
  9. struct __wait_queue { 
  10.     unsigned int flags; 
  11. #define WQ_FLAG_EXCLUSIVE    0x01 
  12.     void *private;//2.6版本是採用void指標,而以前的版本是struct task_struct * task; 
  13.                   //實際在用的時候,仍然把private賦值為task 
  14.     wait_queue_func_t func; 
  15.     struct list_head task_list; 
  16. }; 

struct list_head {<br /> struct list_head *next, *prev;<br />};<br />struct __wait_queue_head {<br /> spinlock_t lock;<br /> struct list_head task_list;<br />};<br />typedef struct __wait_queue_head wait_queue_head_t;<br />struct __wait_queue {<br /> unsigned int flags;<br />#define WQ_FLAG_EXCLUSIVE 0x01<br /> void *private;//2.6版本是採用void指標,而以前的版本是struct task_struct * task;<br /> //實際在用的時候,仍然把private賦值為task<br /> wait_queue_func_t func;<br /> struct list_head task_list;<br />};<br />

所以隊列頭和隊列項是通過list_head聯絡到一起的,list_head是一個雙向鏈表,在linux核心中有著廣泛的應用。並且在list.h中對它有著很多的操作。

2.對列頭和隊列項的初始化:
wait_queue_head_t my_queue;

init_waitqueue_head(&my_queue);

直接定義並初始化。init_waitqueue_head()函數會將自旋鎖初始化為未鎖,等待隊列初始化為空白的雙向迴圈鏈表。

DECLARE_WAIT_QUEUE_HEAD(my_queue);

定義並初始化

3.定義等待隊列: DECLARE_WAITQUEUE(name,tsk);

[cpp]
view plaincopyprint?
  1. #define   DECLARE_WAITQUEUE(name,   tsk)       /
     
  2. wait_queue_t   name     =__WAITQUEUE_INITIALIZER(name,   tsk)  
  3.  
  4. #define   __WAITQUEUE_INITIALIZER(name,   tsk)   {         task:     tsk,        task_list:  {  NULL,   NULL   },  __WAITQUEUE_DEBUG_INI(name)}
     

#define DECLARE_WAITQUEUE(name, tsk) /<br />wait_queue_t name =__WAITQUEUE_INITIALIZER(name, tsk) </p><p>#define __WAITQUEUE_INITIALIZER(name, tsk) { task: tsk, task_list: { NULL, NULL }, __WAITQUEUE_DEBUG_INI(name)}<br />

它的解釋是:
通過DECLARE_WAITQUEUE宏將等待隊列項初始化成對應的任務結構,並且用於串連的相關指標均設定為空白。其中加入了調試相關代碼。
進程通過執行下面步驟將自己加入到一個等待隊列中:
1) 調用DECLARE_WAITQUEUE()建立一個等待隊列的項;
2) 調用add_wait_queue()把自己加入到等待隊列中。該隊列會在進程等待的條件滿足時喚醒它。在其他地方寫相關代碼,在事件發生時,對等的隊列執行wake_up()操作。
3) 將進程狀態變更為: TASK_INTERRUPTIBLE or TASK_UNINTERRUPTIBLE。
4) 如果狀態被置為TASK_INTERRUPTIBLE ,則訊號喚醒進程。即為偽喚醒(喚醒不是因為事件的發生),因此檢查並處理訊號。
5) 檢查condition是否為真,為真則沒必要休眠,如果不為真,則調用scheduled()。
6) 當進程被喚醒的時候,它會再次檢查條件是否為真。真就退出迴圈,否則再次調用scheduled()並一直重複這步操作。
7) condition滿足後,進程將自己設定為TASK_RUNNING 並通過remove_wait_queue()退出。

4.(從等待隊列頭中)添加/移出等待隊列

(1)add_wait_queue()函數: (2)remove_wait_queue()函數:

5.等待事件:(有條件睡眠)

1)wait_event()宏:

[cpp]
view plaincopyprint?
  1. #define wait_event(wq, condition) /
     
  2.  
  3. do { /  
  4. if (condition) /  
  5. break; /  
  6. __wait_event(wq, condition); /  
  7. } while (0)  
  8.   
  9. #define __wait_event_timeout(wq, condition, ret) /
     
  10.  
  11. do { /  
  12. DEFINE_WAIT(__wait); /  
  13. /  
  14. for (;;) { /  
  15. prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE); /  
  16. if (condition) /  
  17. break; /  
  18. ret = schedule_timeout(ret); /  
  19. if (!ret) /  
  20. break; /  
  21. } /  
  22. finish_wait(&wq, &__wait); /  
  23. } while (0)  

#define wait_event(wq, condition) / </p><p>do { /<br />if (condition) /<br />break; /<br />__wait_event(wq, condition); /<br />} while (0) </p><p>#define __wait_event_timeout(wq, condition, ret) / </p><p>do { /<br />DEFINE_WAIT(__wait); /<br />/<br />for (;;) { /<br />prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE); /<br />if (condition) /<br />break; /<br />ret = schedule_timeout(ret); /<br />if (!ret) /<br />break; /<br />} /<br />finish_wait(&wq, &__wait); /<br />} while (0)<br />

在等待會列中睡眠直到condition為真。在等待的期間,進程會被置為TASK_UNINTERRUPTIBLE進入睡眠,直到condition變數變為真。每次進程被喚醒的時候都會檢查condition的值.

(2)wait_event_interruptible()函數:

和wait_event()的區別是調用該宏在等待的過程中當前進程會被設定為TASK_INTERRUPTIBLE狀態.在每次被喚醒的時候,首先檢查condition是否為真,如果為真則返回,否則檢查如果進程是被訊號喚醒,會返回-ERESTARTSYS錯誤碼.如果是condition為真,則返回0.

(3)wait_event_timeout()宏:

也與wait_event()類似.不過如果所給的睡眠時間為負數則立即返回.如果在睡眠期間被喚醒,且condition為真則返回剩餘的睡眠時間,否則繼續睡眠直到到達或超過給定的睡眠時間,然後返回0.

(4)wait_event_interruptible_timeout()宏:

與wait_event_timeout()類似,不過如果在睡眠期間被訊號打斷則返回ERESTARTSYS錯誤碼.

(5) wait_event_interruptible_exclusive()宏

同樣和wait_event_interruptible()一樣,不過該睡眠的進程是一個互斥進程.

6.喚醒隊列:

(1)wake_up()函數:

喚醒等待隊列.可喚醒處於TASK_INTERRUPTIBLE和TASK_UNINTERUPTIBLE狀態的進程,和wait_event/wait_event_timeout成對使用.

2)wake_up_interruptible()函數: #define wake_up_interruptible(x) __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)

和wake_up()唯一的區別是它只能喚醒TASK_INTERRUPTIBLE狀態的進程.,與wait_event_interruptible/wait_event_interruptible_timeout/
wait_event_interruptible_exclusive成對使用.

TASK_INTERRUPTIBLE,允許通過發送signal喚醒它(即可中斷的睡眠狀態);

TASK_UNINTERRUPTIBLE,不接收任何 singal

7.在等待隊列上睡眠:(無條件睡眠,老核心使用,新核心建議不用)

(1)sleep_on()函數:

該函數的作用是定義一個等待隊列(wait),並將當前進程添加到等待隊列中(wait),然後將當前進程的狀態置為TASK_UNINTERRUPTIBLE,並將等待隊列(wait)添加到等待隊列頭(q)中。之後就被掛起直到資源可以擷取,才被從等待隊列頭(q)中喚醒,從等待隊列頭中移出。在被掛起等待資源期間,該進程不能被訊號喚醒。

(2)sleep_on_timeout()函數:

與sleep_on()函數的區別在於調用該函數時,如果在指定的時間內(timeout)沒有獲得等待的資源就會返回。實際上是調用schedule_timeout()函數實現的。值得注意的是如果所給的睡眠時間(timeout)小於0,則不會睡眠。該函數返回的是真正的睡眠時間。

(3)interruptible_sleep_on()函數:

該函數和sleep_on()函數唯一的區別是將當前進程的狀態置為TASK_INTERRUPTINLE,這意味在睡眠如果該進程收到訊號則會被喚醒。

(4)interruptible_sleep_on_timeout()函數:

類似於sleep_on_timeout()函數。進程在睡眠中可能在等待的時間沒有到達就被訊號打斷而被喚醒,也可能是等待的時間到達而被喚醒。

來源:http://blog.csdn.net/funy_liu/article/details/5321147

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.