記錄些等待隊列(wait_queue)的使用

貼幾篇文章先...

https://blog.csdn.net/hs794502825/article/details/8959459

https://blog.csdn.net/lizuobin2/article/details/51785812


記錄些概念和接口。

1. 什麼是睡眠?

cpu調度 有 按時間片輪轉, 搶佔式基於優先級, 實時調度等很多方式。

不同場景使用不同調度方式。

比如Linux就是一個非硬實時的, 搶佔式基於優先級,  也按時間片輪轉的調度系統。

VxWorks, Nuclues等爲實時操作系統(RTOS)。

 

簡單說, 線程被掛起, cpu去幹別的事了,  該線程就算睡眠了...

 

 

2. 如何睡眠?

1).  被動睡眠, 比如時間片到了, cpu調度其他線程。irq中斷來了, cpu去執行isr中斷處理函數等。

2).  主動睡眠,  設置當前狀態爲TASK_INTERRUPTIBLE, 然後調用schedule()或者schedule_timeout()函數。

     會主動放棄cpu, 進入掛起狀態。

 

3. 等待隊列的使用場景?

1). 以IO操作爲例, 用戶態讀寫操作時, 如果內核態文件系統/驅動設備 不滿足情況。通常會阻塞住這次IO調用。

即read, write需要等待設備/數據ready後, 才能讀出,  寫入數據。

內核態有幾種實現方式, 

A. 循環判斷設備狀態/數據是否ready, ok後完成這次IO。 - 這樣子就是白白浪費cpu了。

B. 直接返回-EAGAIN等錯誤,  讓用戶下次再來讀寫...

    這就是非阻塞式IO(但不是異步IO), 比如有些alsa 接口, snd_pcm_read, snd_pcm_write等等。都是非阻塞IO的情況。

    (這種有很多,  只要能返回-EAGAIN那種, 都是非阻塞IO)

C. 依然阻塞方式, 內核態可以使用等待隊列的方式, 主動放棄cpu執行, 如此就能減低cpu負載了。


D. 順便提一句異步IO, 即AIO, 所謂異步, 通常以註冊回調函數的方式來實現。 即註冊讀寫IO 到內核態, 當內核態有IO數據後, 

調用用戶態的IO回調函數,  這就算異步IO。我也用的不多... 先暫時不管了...

E. 哦,  還有種poll, select, epoll這種, 是多路複用IO的接口,  通常一個設備IO即一個fd文件描述符的讀寫, 我們直接使用read, write函數阻塞等待就是了。 但如果用戶態進程, 需要同時監聽多個設備的IO, 一般來說就幾種方式...

     (1) 起多進程, 或者多線程,  每個線程獨立讀寫對應設備。 - 浪費...

     (2) 單個進程, 循環挨個讀寫設備....  - 浪費...

     (3) 多路複用IO, poll, select, epoll 一個文件描述符的數組, 當數組內的設備IO 準備就緒後, 在針對性地執行讀寫操作。 - 好辦            法!


3. 如何使用等待隊列?

差點又忘了正題,  關於如何使用等待隊列。 內核中已經封裝好一些接口。

1). 創建等待隊列頭部, 

DECLARE_WAIT_QUEUE_HEAD(name)

或者

wait_queue_head_t my_queue;

init_waitqueue_head(&my_queue);

 

2). 簡單睡眠...

內核中定義了很多幫助宏, 創建完等待隊列後, 簡單使用以下宏就可以使當前線程掛起並進入等待隊列。

wait_event(queue, condition)

wait_event_interruptible(queue, condition)

wait_event_timeout(queue, condition, timeout)

wait_event_interruptible_timeout(queue, condition, timeout)

 

*簡單睡眠如何喚醒。兩個宏

void wake_up(wait_queue_head_t *queue)

void wake_up_interruptible(wait_queue_head_t *queue)

 

3). 手動睡眠

稍微複雜點, 不用上面那些宏。

在第一步已經創建了等待隊列頭部,

A. 下面創建一個等待隊列條目。

DECLARE_WAITQUEUE(name, task)

 

B. 將等待隊列條目 放入等待隊列中

void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)

void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait)

void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)

 

C. 設置線程狀態

set_current_state(TASK_INTERRUPTIBLE)

D. 進程調度

schedule() 或者 schedule_timeout()


關於內核中如何實現...後面看懂了繼續。

 

總結一下:

如何使用等待隊列,  簡單明瞭:

1. 創建等待隊列頭部, 創建等待隊列項目。

2. 將等待隊列條目加入等待隊列中。

3. 設置當前進程/線程狀態。

4. 進程/線程調度。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章