關於IO的同步,異步,阻塞,非阻塞

    關於網絡IO的同步、異步、阻塞、非阻塞的文章網上有很多,搜索了對比了一下,觀點也各不相同,即使是wiki也把異步和非阻塞區分得不是很清楚。下面我就結合《Unix網絡編程 卷1》中的介紹,來說一說自己的理解。

    IO模型

    首先我們要先知道目前unix存在的五種IO模型,分別是:

  •     阻塞型IO(blocking I/O)
  •     非阻塞型IO(noblocking I/O)
  •     IO多路複用(I/O multiplexing)
  •     信號驅動(signal driven I/O)
  •     異步IO(asynchronous I/O)



    關於這五種模型這裏就不詳細介紹,大家有興趣的話可以參考這篇博文,寫的很詳細:http://blog.csdn.net/sunyubo458/article/details/6096723


    IO的兩個階段

    1.等待數據準備好

    2.將數據從內核緩衝區複製到用戶進程緩衝區


    同步,異步的區別

    那麼究竟什麼是同步和異步的區別呢?我的總結如下:

  •     同步IO,需要用戶進程主動將存放在內核緩衝區中的數據拷貝到用戶進程中。
  •     異步IO,內核會自動將數據從內核緩衝區拷貝到用戶緩衝區,然後再通知用戶。

    這樣,同步和異步的概念就非常明顯了。以上的五種IO模型,前面四種都是同步的,只有第五種IO模型纔是異步的IO。


    阻塞和非阻塞

    那麼阻塞和非阻塞呢?注意到以上五個模型。阻塞IO,非阻塞IO,只是上面的五個模型中的兩個。阻塞,非阻塞,是針對單個進程而言的。

    我們先從阻塞和非阻塞socket來簡單理解一下二者的區別:通常的,對一個文件描述符指定的文件或設備, 有兩種工作方式: 阻塞與非阻塞方式。

    (1). 阻塞方式是指: 當試圖對該文件描述符進行讀寫時,如果當時沒有數據可讀,或者暫時不可寫,程序就進入等待狀態,直到有東西可讀或者可寫爲止。

    (2). 非阻塞方式是指: 如果沒有數據可讀,或者不可寫,讀寫函數馬上返回,而不會等待。

    (3). 舉個例子來說,比如說小明去找一個女神聊天,女神卻不在。 如果小明捨不得走,只能在女神大門口死等着,當然小明可以休息。當女神來了,她會把你喚醒(因爲擋着她門了),這就是阻塞方式。如果小明發現女神不在,立即離開,以後每隔十分鐘回來看一下(採用輪詢方式),不在的話仍然立即離開,這就是非阻塞方式。

    (4). 阻塞方式和非阻塞方式唯一的區別: 是否立即返回。

   

    下面我們就來進行更深層次地理解

    當對多路複用IO進行調用時,比如使用poll。需注意的是,poll是系統調用,當調用poll的時候,其實已經是陷入了內核,是內核線程在跑了。因此對於調用poll的用戶進程來講,此時是阻塞的。

    因爲poll的底層實現,是去掃描每個文件描述符(fd),而如果要對感興趣的fd進行掃描,那麼只能將每個描述符設置成非阻塞的形式(對於用戶進程來講,設置fd是阻塞還是非阻塞,可以使用系統調用fcntl),這樣纔有可能進行掃描。如果掃描當中,發現有可讀(如果可讀是用戶感興趣的)的fd,那麼select就在用戶進程層面就會返回,並且告知用戶進程哪些fd是可讀的。

    這時候,用戶進程仍然需要使用read的系統調用,將fd的數據,從內核緩衝區拷貝到用戶進程緩衝區(這也是poll爲同步IO的原因)。

    那麼此時的read是阻塞還是非阻塞的呢?這就要看fd的狀態了,如果fd被設置成了非阻塞,那麼此時read就是非阻塞的,否則就是阻塞的。不過程序已經執行到了這時候,不管fd是阻塞還是非阻塞,都沒有任何區別,因爲此前的poll,就是知道有數據準備好了才返回的,也就是說內核和緩衝區已經有了數據,此時進行read,是肯定能夠將數據拷貝到用戶進程的緩衝區的。

    但如果換種想法,如果poll是因爲超時返回的,而我們又對一個fd(此時fd是被poll輪詢過的)進行調用,那麼此時是阻塞還是非阻塞,就非常有意義了。


    結論

    1.判斷IO是同步還是異步,是看誰主動將數據拷貝到用戶進程

    2.select或者poll,epoll,是同步調用

發佈了58 篇原創文章 · 獲贊 1169 · 訪問量 37萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章