1. 程式人生 > >linux的同步,非同步,阻塞,非阻塞

linux的同步,非同步,阻塞,非阻塞

linux中關於IO操作有同步,非同步,阻塞,非阻塞幾種模式,這幾種模式可能有些同學會有點迷糊,把同步和阻塞混為一起,把非同步和非阻塞混一起.其實這四種模式的關係是:阻塞和非阻塞都屬於同步.

1. 基礎知識     我們都知道linux將所有的裝置都看作檔案,那麼我們對linux的裝置操作都可以看做是檔案操作.我們開啟一個檔案的時候核心會返回給我們一個檔案描述符,那麼我們對檔案的操作都是檔案描述符來操作的.     系統呼叫是如何完成IO操作的呢?網上有一個系列文章講解一次IO操作的真實過程<一個IO的傳奇一生>.     linux將記憶體分為核心區,使用者區; linux核心給我們管理所有的硬體資源,應用程式通過呼叫系統呼叫和核心互動,達到使用硬體資源的目的; 應用程式通過系統呼叫read發起一個讀操作;這時候核心建立一個檔案描述符,並通過驅動程式向硬體傳送讀指令,並將讀的的資料放在這個描述符對應結構體的快取區。但這個結構體是在核心記憶體區的。需要將這個資料讀到使用者區。這樣完成了一次讀操作;
    但是大家都知道I/O裝置相比cpu的速度是極慢的。linux提供的read系統呼叫,也是一個阻塞函式。這樣我們的應用程序在發起read系統呼叫時,就必須阻塞,就程序被掛起而等待檔案描述符的讀就緒;     這裡,我們先了解一下,什麼是檔案描述符讀就緒,什麼是寫就緒?     讀就緒:就是這個檔案描述符的接收緩衝區中的資料位元組數大於等於套接字接收緩衝區低水位標記的當前大小;     寫就緒:該描述符傳送緩衝區的可用空間位元組數大於等於描述符傳送緩衝區低水位標記的當前大小.     接收低水位標記和傳送低水位標記:由應用程式指定,比如應用程式指定接收低水位為64個位元組。那麼接收緩衝區有64個位元組,才算fd讀就緒
2. 各種IO模式比較    從上面我們知道一個IO操作包含了基本的兩步:描述符就緒,核心資料到使用者資料的拷貝.一次IO操作可能需要花費幾秒鐘甚至更長的時間.    阻塞:如果檔案描述符還沒就緒那麼就一直等待,直到描述符就緒ok.等到描述符就緒ok以後就開始其他的IO步驟,最後完成IO操作以後返回. 非阻塞:如果檔案描述符還沒就緒那麼就直接返回並返回一個錯誤碼,不再傻等到描述符就緒. 阻塞和非阻塞的區別就是:如果此時因為各種原因不能馬上進行IO操作那麼如果繼續等待則是阻塞IO,否則為非阻塞IO. 同步:請求阻塞,等待一次IO操作全部完成再返回.這裡的一次IO操作包含了上面的阻塞和非阻塞模式,也就是這次IO操作可能成功也有可能會失敗,但是一定要等待IO操作全部完成再返回.
非同步:請求不阻塞,不等待IO操作完成再返回.等到IO操作完成以後核心會通知我們IO操作已經完成. 同步和非同步的區別就是:等待一次IO操作完成再返回則是同步,否則為非同步. 我們知道訊號是一種非同步通知的方式,那麼IO操作加上訊號操作是不是就可以變成非同步IO? 非同步非阻塞(訊號驅動式IO):核心在描述符就緒時傳送SIGIO訊號通知程序,程序通過訊號處理函式接收資料.這就是上面提到的加上非同步的訊號就瞬時變成了高大上的非同步IO了,但是這種方式和真正的非同步IO還是有一些區別的,非同步IO(AIO)是等IO操作完成以後傳送通知(不是通過訊號的方式),但是訊號驅動的非同步IO是等描述符就緒傳送通知,而不是等IO操作全部完成,我們需要在訊號處理函式中再去同步的讀取資料(只是此時我們不會因為描述符還沒準備好而阻塞了). 非同步非阻塞(IO複用):linux提供了select,poll,程序可以將一個或多個fd傳遞給select.select系統呼叫會阻塞直到其中的某一個fd就緒,此時我們再呼叫read等操作就不會因為描述符未就緒而阻塞,但是其實跟上面的訊號驅動IO也是一樣的.所以我個人認為應該把這種模式改成非同步阻塞IO.