Linux的阻塞與非阻塞

来源:互联网 发布:淘宝蜂蜜店铺推荐 编辑:程序博客网 时间:2024/06/04 01:39
Linux的阻塞與非阻塞
在了解阻塞與非阻塞之前,先來了解下,阻塞與非阻塞是怎麼來的。
假設需要些一個應用程序,對一個設備進行讀寫。在應用層,在使用open的函數打開設備之後,會對設備進行read或者write的操作。

這時候會發生以下兩種種情況:
(1)設備可以讀寫成功;
(2)設備不可以讀寫成功;

注:讀寫不成功的原因可能是,設備不可以讀寫,也有可能是空間不夠不能夠讀寫。
讀寫不成功怎麼辦,是立即返回嗎?還是等待可以讀寫?當讀寫不成功,程序立即返回 ,這種方式叫作非阻塞;當程序讀寫不成功沒有立即返回,在等待可以讀寫成功,叫作阻塞。

小明與小紅的故事(1)
假設小明想約女朋友小紅今天晚上一起吃飯。
小明:“小紅今晚一起吃飯唄”
小紅有兩種回答,
(1)小紅:“可以沒問題。”
(2)小紅:“我很想今晚跟你去吃飯,但是今晚有事”。

這時候小明也有兩種回答
(1)小明:“哦,那就算了,下次吧”
(2)小明:“沒事啊,我等你,等你忙完,我們再一起去”。
小明的回答前者,下次再說屬於阻塞,後者等小紅忙完屬於非阻塞。也就是說,應用層在執行read或者write函數后,會調用驅動的read或者write函數,假設不能讀寫成功,應用程序會有兩種處理方式,(1)像小明一樣等待,等到設備有空進行read或者write,這個時候應用不做任何的事情,只是等待。(2)這次直接返回,下次在說。

在操作系統中,CPU都是比較重要的資源,任何一個程序要運行都是要經過CPU運算的,直接佔用CPU等待,那明顯就是浪費資源了。反正應用程序在的只是在等待資源,對於這種程序,操作系統讓它先進入休眠的,等到有資源了再將其喚醒。也就是說當應用程序以阻塞的方式訪問的設備的時候,當訪問不成功,應用程序不能一直在CPU等待,會進入休眠,等到設備可以讀寫了,進行應用程序的喚醒,再次執行還沒有執行完的操作。
小明與小紅的故事(2)
小明決定等待小紅后,假設小明在他哥們(小華)的一個飯店等小紅,於是去到哥們的飯館就霸佔一張大桌子,恰好那天哥們的飯館的人生意不錯,桌子不夠用。這時候小華就會找小明聊天。
小華:“小明,小紅還不知道什麼時候才來,你看現在桌子不夠用,那你先把桌子讓出來先,等下小紅來了。再把桌子給你。”
小明一聽,心裡想:“也是,平常小紅加班都要到九點多,現在才六點多,而且客人有多,佔這麼大的桌子不合適”
於是就小明讓出了桌子,先去逛商場了。
直到九點鐘,小紅來的時候,小華趕緊打個電話給小明叫回來,并找一張桌子給小明與小紅吃飯。

linux下是怎麼進入進程read和wirte函數是怎麼進行這一個阻塞的過程的
當應用程序不能實現read和write函數的時候,會讓出CPU(也就轉進程調度),直到設備可以進行了read和write的時候,將應用程序喚醒。繼續進行read和write的操作。因為應用程序只是選擇設備以阻塞或者非阻塞的方式打開,因此具體的阻塞與非阻塞方法需要在驅動中完成的。阻塞在驅動程序的實現,可以通過等待隊列來實現的。

先來理解下什麼是等待隊列
等待隊列:由循環實現,其元素包括指向進程描述符的指針,每個等待隊列都有個等待隊列的頭。抽象來說,存在是個環形的線,將等待隊列串起來,每個的等待隊列的頭,相當於鉤子,直接掛在環形的線上,等待隊列後面是一個個的進程(實際是並不是直接掛在著進程,而是進程指針,由進程指針指向進程)
實現阻塞的過程
(1)定義“等待序列頭”
wait_queue_head_t my_queue; 

(2)初始化等待隊列頭
init_waitqueue_head(&my_qeeue);

(3)定義隊列元素
DECLARE_WAIT_QUEUE(name,task);

(4)添加隊列元素
void add_wait_queue(wait_queue_head_t *p,wait_queue_head *wait);

(5)等待事件
void wait_even_interruptible(queue,condition);

(6)進行喚醒
wake_upinterruptible(wait_queue_head_t *p)

(7)將元素移出等待隊列
void remove_wait_queue(wait_queue_head_t *p,wait_queue_head *wait);