貼幾篇文章先...
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. 進程/線程調度。