linux 的五種I/O模式

本文主要轉自http://www.cnblogs.com/chy2055/p/5220793.html

 一、關於I/O模型的引出

  我們都知道,爲了OS的安全性等的考慮,進程是無法直接操作I/O設備的,其必須通過系統調用請求內核來協助完成I/O動作,而內核會爲每個I/O設備維護一個buffer如下圖所示:


整個請求過程爲: 用戶進程發起請求,內核接受到請求後,從I/O設備中獲取數據到buffer中,再將buffer中的數據copy到用戶進程的地址空間,該用戶進程獲取到數據後再響應客戶端。

用戶空間和內核空間:現在操作系統都是採用虛擬存儲器,那麼對32位操作系統而言,它的尋址空間(虛擬存儲空間)爲4G(2的32次方)。操作系統的核心是內核,獨立於普通的應用程序,可以訪問受保護的內存空間,也有訪問底層硬件設備的所有權限。爲了保證用戶進程不能直接操作內核(kernel),保證內核的安全,操心繫統將虛擬空間劃分爲兩部分,一部分爲內核空間,一部分爲用戶空間。針對linux操作系統而言,將最高的1G字節(從虛擬地址0xC0000000到0xFFFFFFFF),供內核使用,稱爲內核空間,而將較低的3G字節(從虛擬地址0x00000000到0xBFFFFFFF),供各個進程使用,稱爲用戶空間。

在整個請求過程中,數據輸入至buffer需要時間,而從buffer複製數據至進程也需要時間。因此根據在這兩段時間內等待方式的不同,I/O動作可以分爲以下五種模式:

  (1) 阻塞I/O (Blocking I/O)

  (2) 非阻塞I/O (Non-Blocking I/O)

  (3) I/O複用(I/O Multiplexing)

  (4) 信號驅動的I/O (Signal Driven I/O)

  (5) 異步I/O (Asynchrnous I/O)

關於進程切換:

從一個進程的運行轉到另一個進程上運行,這個過程中經過下面這些變化:
          保存處理機上下文,包括程序計數器和其他寄存器。
          更新PCB信息。
          把進程的PCB移入相應的隊列,如就緒、在某事件阻塞等隊列。
          選擇另一個進程執行,並更新其PCB。
          更新內存管理的數據結構。
          恢復處理機上下文。

關於進程的阻塞:

正在執行的進程,由於期待的某些事件未發生,如請求系統資源失敗、等待某種操作的完成、新數據尚未到達或無新工作做等,則由系統自動執行阻塞原語(Block),使自己由運行狀態變爲阻塞狀態。可見,進程的阻塞是進程自身的一種主動行爲,也因此只有處於運行態的進程(獲得CPU),纔可能將其轉爲阻塞狀態。當進程進入阻塞狀態,是不佔用CPU資源的。

關於文件描述符:

文件描述符在形式上是一個非負整數。實際上,它是一個索引值,指向內核爲每一個進程所維護的該進程打開文件的記錄表。當程序打開一個現有文件或者創建一個新文件時,內核向進程返回一個文件描述符。在網絡中,一個socket對象就是1個文件描述符,在文件中,1個文件句柄(即file對象)就是1個文件描述符。其實可以理解爲就是一個“指針”或“句柄”,指向1個socket或file對象,當file或socket發生改變時,這個對象對應的文件描述符,也會發生相應改變。

二、關於I/O模型的劃分

  阻塞:調用的進程一直處於等待狀態,直到操作完成。

  非阻塞:在內核的數據還未準備好時,會立即返回,進程可以去幹其他事情。

從同步異步,以及阻塞、非阻塞兩個維度來劃分來看:

    

同步/異步主要針對Client端: 

同步:所謂同步,就是在Client端發出一個功能調用時,在沒有得到結果之前,該調用就不返回。也就是必須一件一件事做,等前一件做完了才能做下一件事,因此這裏同步指的是功能調用者本身沒有得到結果

異步的概念和同步相對。當Client端一個異步過程調用發出後,調用者不能立刻得到結果。實際處理這個調用的部件在完成後,通過狀態、通知和回調來通知調用者。

阻塞/非阻塞主要針對S端:

阻塞調用是指調用結果返回之前,當前線程會被掛起(線程進入非可執行狀態,在這個狀態下,cpu不會給線程分配時間片,即線程暫停運行)。函數只有在得到結果之後纔會返回。

非阻塞:
      非阻塞和阻塞的概念相對應,指在不能立刻得到結果之前,該函數不會阻塞當前線程,而會立刻返回。

同步與非同步

阻塞和非阻塞是指當server端的進程訪問的數據如果尚未就緒,進程是否需要等待,簡單說這相當於函數內部的實現區別,也就是未就緒時是直接返回還是等待就緒;
  而同步和異步是指client端訪問數據的機制,同步一般指主動請求並等待I/O操作完畢的方式,當數據就緒後在讀寫的時候必須阻塞(區別就緒與讀寫二個階段,同步的讀寫必須阻塞),異步則指主動請求數據後便可以繼續處理其它任務,隨後等待I/O,操作完畢的通知,這可以使進程在數據讀寫時也不阻塞。(等待"通知")

  總之,同步IO和異步IO的區別就在於:數據訪問的時候進程是否阻塞!
     阻塞IO和非阻塞IO的區別就在於:應用程序的調用是否立即返回!


三、I/O模型分述

1、阻塞I/O

     

  從上圖可以看到在整個過程中,當用戶進程進行系統調用時,內核就開始了I/O的第一個階段,準備數據到緩衝區中,當數據都準備完成後,則將數據從內核緩衝區中拷貝到用戶進程的內存中,這時用戶進程才解除block的狀態重新運行。

  所以,Blocking I/O的特點就是在I/O執行的兩個階段都被block了。

2、非阻塞I/O

     

  從上圖可以看到在I/O執行的兩個階段中,用戶進程只有在第二個階段被阻塞了,而第一個階段沒有阻塞,但是在第一個階段中,用戶進程需要盲等,不停的去輪詢內核,看數據是否準備好了,因此該模型是比較消耗CPU的。

3、I/O複用

    

   從上圖可以看到在I/O複用模型中,I/O執行的兩個階段都是用戶進程都是阻塞的,但是兩個階段是獨立的,在一次完整的I/O操作中,該用戶進程是發起了兩次系統調用。

4、信號驅動的I/O

     

  該模型也叫作基於事件驅動的I/O模型,可以看到該模型中,只有在I/O執行的第二階段阻塞了用戶進程,而在第一階段是沒有阻塞的。

  乍看起來感覺和非阻塞模型很相似,其實不同之處就在於,該模型在I/O執行的第一階段,當數據準備完成之後,會主動的通知用戶進程數據已經準備完成,即對用戶進程做一個回調。該通知分爲兩種,一爲水平觸發,即如果用戶進程不響應則會一直髮送通知,二爲邊緣觸發,即只通知一次。

 5、異步I/O

     

  在該模型中,當用戶進程發起系統調用後,立刻就可以開始去做其它的事情,然後直到I/O執行的兩個階段都完成之後,內核會給用戶進程發送通知,告訴用戶進程操作已經完成了。

對unix來講:阻塞式I/O(默認),非阻塞式I/O(nonblock),I/O複用(select/poll/epoll),信號驅動IO都屬於同步I/O,因爲它們在數據由內核空間複製回進程緩衝區時都是阻塞的(不能幹別的事)。只有異步I/O模型(AIO)是符合異步I/O操作的含義的,即在1數據準備完成、2由內核空間拷貝回緩衝區後 通知進程,在等待通知的這段時間裏可以幹別的事。異步I/O跟信號驅動I/O的不同之處在於,它不用調用recv進行數據的複製,如果將後者比做”拉pull“,則前者可以認爲是”push推“,push的效率會高點,

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章