I/O模型

在討論I/O模型之前,先看下標準輸入。標準輸入一般分爲分爲兩個不同的階段:

  1. 等待數據準備好,也就是到達內核的某個緩衝區
  2. 將數據從內核緩衝區複製到應用進程緩衝區

不同的I/O模型就是對上述兩個階段作不同的處理,以及兩個階段之間的銜接也不同。I/O模型一般有如下5種:

  1. 阻塞式I/O
  2. 非阻塞式I/O
  3. I/O複用
  4. 信號驅動式I/O
  5. 異步I/O

一、阻塞式I/O

        阻塞式I/O是最流行的I/O模型。默認情形下,所有套接字都是阻塞的。

        如上圖所示,應用進程系統調用recvfrom,但是直到數據包到達並且複製到應用進程的緩衝區才返回。可以說進程從調用recvfrom開始到數據複製到應用進程緩衝區並返回的整段時間內都是阻塞的,一直到recvfrom返回成功指示後,應用進程纔開始處理數據。注意,此處只調用了一次recvfrom系統調用。

二、非阻塞I/O

        應用進程會首先把套接字設置成非阻塞的。

        由上圖可以看到,應用進程會一直對非阻塞描述符循環調用recvfrom,直到數據複製到應用進程緩衝區,並返回成功指示爲止。這麼做往往會消耗更多的cpu資源,很少會遇到。

三、I/O複用

        關於前面兩種模型,應用進程都是阻塞在recvfrom系統調用上。而I/O複用則是將阻塞狀態轉移到上一層,如select或poll等,阻塞在這兩個系統調用中的其中一個之上。

這裏以select爲例子進行分析。如上圖,應用進程阻塞於select調用,等到數據包準備好,也就是到達內核某個緩衝區時,再調用recvfrom把數據進一步複製到應用進程緩衝區。乍一看I/O複用並沒什麼優勢,相較前兩種反而多了一次系統調用,但是它可以同時監聽多個文件描述符,這在高併發情況下將會有巨大優勢。

四、信號驅動式I/O

        當描述符就緒後,內核也可以通過SIGIO信號通知應用進程。

        首先需要開啓套接字的信號驅動式I/O功能,並通過sigaction系統調用安裝一個信號處理函數,該系統調用將立即返回,應用進程得以繼續工作其它的事。待數據報準備好,已在內核緩衝區時,內核就爲該進程產生一個SIGIO信號,隨後就可以在信號處理函數中進行recvfrom系統調用,將數據從內核緩衝區複製到應用進程緩衝區,並返回成功指示。

        這種模型最大的優勢在於應用進程在等待數據報準備期間不被阻塞,主程序可以繼續執行,只需在收到來自信號處理函數的通知後開始recvfrom系統調用即可。

五、異步I/O

        異步I/O是由POSIX規範定義的,主要是調用滿足POSIX規範的函數。這些函數工作機制一般是:告訴內核啓動某個操作,並讓內核在某個操作(包括將數據從內核緩衝區複製到應用進程緩衝區)完成後通知應用進程。

        這裏調用aio_read函數,給內核傳遞描述符、緩衝區指針、緩衝區大小和文件偏移,並告訴內核當整個操作完成時如何通知應用進程。同時,該系統調用立即返回,在等待I/O完成期間,應用進程也不被阻塞。這一點與信號驅動式I/O的主要區別在於:信號驅動式I/O是由內核通知應用進程何時啓動I/O操作,而異步I/O模型則通知應用進程I/O操作何時完成。

總結

        可以看出前4中模型的主要區別在於第一階段,第二階段也就是數據從內核緩衝區複製到應用進程緩衝區這一階段都是相同的,應用進程在這期間都是阻塞的,而異步I/O模型在這期間也不被阻塞,所以前4種模型也都是同步I/O模型。