字元驅動之四阻塞IO(等待隊列)

來源:互聯網
上載者:User
我們經常看到 read 的時候沒有資料可讀,而有時卻是 write 的時候緩衝區已 滿寫不進去。而應用程式不關心這個,只關心我要的資料何時能讀取出來,或者我 寫的資料何時才能寫進去。因此這樣應該要阻塞進程,直到有資料可讀或者有記憶體 可寫。那我們就來看看幾個概念和問題:     1)何為進程睡眠?       2)是否什麼情況下都可以睡眠?     3)既然睡眠了,如何喚醒?     4)如何操作阻塞I/O?       1、所謂進程睡眠:當一個進程的狀態被置為睡眠之後,它將等待啟動並執行隊列中 刪除,一直到該狀態被改變,否則它將不會在任何的 CPU 上運行。簡單的說睡眠的 進程將得不到進程發送器調度,讓出 CPU,被擱置到系統的一邊。     2、看完了睡眠,那我們也來看看哪些情況不可以睡眠,為什麼呢?在<<linux 裝置驅動程式>>中,指出:當你運行在原子上下文時不能睡眠。而原子操作包含有 自旋鎖、BKL、RCU、seqlock、中斷上下文。到了這裡,大家有個疑惑,那訊號量為 何可以睡眠呢?那我們先來看看原子操作的概念吧,從字面來看,它應該採用了物 理學的物質微粒的概念,應該是不可再分的操作啊==>所謂原子操作,就是該操作絕 不會在執行完畢前被任何其他任務或事件打斷(連中斷也不行嗎?),也就說,它的 最小的執行單位,不可能有比它更小的執行單位。在單核 CPU 中,原子操作至少保 證了兩點:<在SMP中,我不是很清楚,就不多做解釋了,若有人知道,可告知哦>     1)原子操作是最小的執行單位,一口氣執行完畢,任何打斷都無效;        2)保護了共用資源的完整性,不被破壞。     自旋鎖禁止CPU搶佔,而訊號量允許CPU搶佔。在單 CPU 情況下,若持有自旋鎖 的進程進入睡眠,由于禁止了CPU搶佔,其他進程將永遠得不到CPU執行,將喚不醒 自旋鎖,你說那系統豈不進入睡眠狀態啊。那中斷呢?能否喚醒自旋鎖睡眠呢?一 般而言,中斷程式能正常運行,但在中斷程式中幾乎不會做喚醒自旋鎖的可能(除 非專門設計),所以系統也將處於睡眠狀態。而對SMP就不同了,因為各自的CPU執行 各自的程式,而自旋鎖只是禁止自己的CPU搶佔而又當前睡眠而已,所以SMP可以喚 醒自旋鎖,但是這樣做,還是比較危險的啊!!而訊號就不同了,它允許CPU搶佔。     中斷一般操作就是進入中斷後,就把關掉中斷,直到中斷結束再重啟中斷。若 我們關了本地中斷後睡眠,任何一個操作中斷IO的進程都會睡眠,一旦喚醒之後, 多個進程為了搶佔資源而並發,從而會導致共用資料的破壞,更有甚者將造成進程 死結啊。      到了這裡,應該知道了為何原子操作不能睡眠了吧,兩方面:一方面不要進程 睡眠,結果導致了系統睡眠或造成死結,另一方面是保護共用資源。      3、有了睡眠,當然就要有喚醒啦。要不睡眠將毫無意義,因為睡眠只是為了 等候到自己所要的東西,取到東西必須返回啊。比如說:你等到的有資料,你一高 興就屁顛屁顛的跑了,哪裡還會在那裡傻等啊;同時你好不容易等到有記憶體寫進去 啦,當然馬上寫入,然後就跑出去玩了。      4、睡眠IO操作方法:             使用睡眠IO需要考慮的三個問題:什麼情況需要睡眠?什麼情況得喚醒? 為何要睡眠? 
#include <linux/wait.h>第一步:【定義等待隊列頭並初始化】/* <動態申請等待隊列> * @brief             初始化等待隊列頭 * @param[in]        queue 我們所要等待的隊列 * @return            no *///wait_queue_head_t my_queue;                    /*定義等待隊列*/init_waitqueue_head(wait_queue_head_t *queue);   /*初始化*//*<靜態申請等待隊列> * @brief             初始化等待隊列頭 * @param[in]        queue 我們所要等待的隊列 * @return            no */DECLARE_WAIT_QUEUE_HEAD(wait_queue_head_t *queue);第二步:【有條件的睡眠】[NOTE]看你要選擇哪種睡眠方式,還有一種無條件睡眠方式這裡沒介紹/* * @brief     不可中斷的睡眠 * @param[in] queue 我們所要等待的隊列《注意它是"通過值"傳遞的》 * @param[in] condition 條件是一任意的布林運算式;它不應當有任何邊界效應. * @return    添加成功返回 0;       */wait_event(queue, condition)/* * @brief             可中斷的睡眠 * @param[in]        queue 我們所要等待的隊列《注意它是"通過值"傳遞的》 * @param[in] condition 條件是一任意的布林運算式;它不應當有任何邊界效應. * @param[in] timeout 等待一段有限的時間後睡眠 * @return         */wait_event_timeout(queue, condition, timeout)/* * @brief     可中斷的睡眠 * @param[in] queue 我們所要等待的隊列《注意它是"通過值"傳遞的》 * @param[in] condition 條件是一任意的布林運算式;它不應當有任何邊界效應. * @return    添加成功返回0;若中斷返回-ERESTARTSYS          */【說明】它被喚醒不單單是condition條件為真的時候,還有中斷的時候。wait_event_interruptible(queue, condition)wait_event_interruptible_timeout(queue, condition, timeout)第三步:【睡眠的喚醒】/* * @brief             喚醒給定隊列的所有進程 * @param[in]        queue 我們所要等待的隊列《注意它是"通過值"傳遞的》 * @return            no */【注意】若喚醒多個進程,則會產生競態。Q:要如何進行處理呢? void wake_up(wait_queue_head_t *queue);/* * @brief             喚醒給定隊列的可中斷的所有進程 * @param[in]        queue 我們所要等待的隊列《注意它是"通過值"傳遞的》 * @return            no */void wake_up_interruptible(wait_queue_head_t *queue);

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.