1. 程式人生 > >圖解UNIX的I/O模型

圖解UNIX的I/O模型

一、簡述

UNIX系統將所有的外部裝置都看作一個檔案來看待,所有開啟的檔案都通過檔案描述符來引用。檔案描述符是一個非負整數,它指向核心中的一個結構體。當開啟一個現有檔案或建立一個新檔案時,核心向程序返回一個檔案描述符。而對於一個socket的讀寫也會有相應的檔案描述符,稱為socketfd(socket描述符)。
在UNIX系統中,I/O輸入操作(例如標準輸入或者套接字的輸入)通常包含以下兩個不同的階段:

  • 等待資料準備好
  • 從核心向程序複製資料

例如對於套接字的輸入,第一步是等待資料從網路中到達,當所等待的資料到達時,資料被複制到核心中的緩衝區。第二步則是把資料從核心緩衝區複製到應用程序的緩衝區。
根據在這兩個不同階段處理的不同,可以將I/O模型劃分為以下五種型別:

  • 阻塞式I/O模型
  • 非阻塞式I/O模型
  • I/O複用
  • 訊號驅動式I/O
  • 非同步I/O

二、I/O模型

為簡單起見,我們以UDP套接字中的recvfrom函式作為系統呼叫來說明I/O模型。recvfrom函式類似於標準的read函式,它的作用是從指定的套接字中讀取資料報。recvfrom會從應用程序空間執行切換到核心空間中執行,一段時間後會再切換回來。有關recvfrom函式的介紹,可以參考本文的參考資料3。

2.1 阻塞式I/O模型

阻塞式I/O模型可以說是最簡單的I/O模型。

阻塞式I/O模型
圖1:阻塞式I/O模型

圖1是阻塞式I/O模型的示意圖,閱讀此圖須注意箭頭的方向,沿著剪頭方向順時針閱讀。
圖1中,應用程序呼叫recvfrom,然後切換到核心空間中執行,直到資料報到達且被複制到應用程序緩衝區中才返回。我們說程序從呼叫recvfrom開始到它返回的整段時間內是被阻塞的。recvfrom成功返回後,應用程序開始處理資料報。

2.2 非阻塞式I/O模型

程序把一個套接字設定為非阻塞是指,在等待I/O資料時,程序並不阻塞,如果資料還沒準備好,則直接返回一個錯誤。

非阻塞式I/O模型
圖2:非阻塞式I/O模型

圖2是非阻塞I/O模型的示圖。
在前兩次呼叫recvfrom時由於資料報沒準備好,因此核心馬上返回一個系統呼叫錯誤。第3次呼叫recvfrom時,資料報已準備好,資料報被複制到應用程序的緩衝區,接著recvfrom成功返回。
當一個應用程序像這樣不斷對一個非阻塞描述符迴圈呼叫recvfrom時,我們稱之為輪詢。應用程序會持續輪詢核心,以確定某個操作是否就緒。輪詢操作會消耗大量的CPU時間。

2.3 I/O複用模型

我們常用的select和poll函式使用了I/O複用模型。我們以select為例說明I/O複用模型的特點。

I/O複用模型
圖3:I/O複用模型

圖3是I/O複用模型的示意圖。
當我們呼叫select函式時,將會阻塞於此函式,等待資料報套接字變為可讀。當等待的多個套接字中的其中一個或者多個變得可讀時,我們呼叫recvfrom把資料報復制到應用程序緩衝區。
比較圖3與圖1,I/O複用模型好像沒什麼優勢,而且應用程序為了獲取資料報,還得增加了一個額外的select系統呼叫。不過I/O複用模型的優勢在於可以同時等待多個(而不只是一個)套接字描述符就緒。

2.4 訊號驅動式I/O模型

訊號驅動I/O模型用得比較少,圖4是該模型的示意圖。

訊號驅動式I/O模型
圖4:訊號驅動式I/O模型

為了使用該I/O模型,需要開啟套接字的訊號驅動I/O功能,並通過sigaction系統呼叫安裝一個訊號處理函式。sigaction函式立即返回,我們的程序繼續工作,即程序沒有被阻塞。當資料報準備好時,核心會為該程序產生一個SIGIO訊號,這樣我們可以在訊號處理函式中呼叫recvfrom讀取資料報,也可以在主迴圈中讀取資料報。無論如何處理SIGIO訊號,這種模型的優勢在於等待資料報到達期間不被阻塞。

2.5 非同步I/O模型

非同步I/O模型的工作機制是,啟動某個操作,並讓核心在整個操作(包括等待資料和將資料從核心複製到使用者空間)完成後通知應用程序。

非同步I/O模型
圖5:非同步I/O模型

圖5是非同步I/O模型的示意圖。我們呼叫aio_read函式,告訴核心,當整個I/O操作完成後通知我們。該系統呼叫立即返回,而在等待I/O完成期間,應用程序不會被阻塞。當I/O完成(包括資料從內樣複製到使用者程序)後,核心會產生一個訊號通知應用程序,應用程序對資料報進行處理。
非同步I/O模型與訊號驅動式I/O的區別在於:訊號驅動式I/O在資料報準備好時就通知應用程序,應用程序還需要將資料報從核心複製到使用者程序緩衝區;而非同步I/O模型則是整個操作完成才通知應用程序,應用程序在整個操作期間都不會被阻塞。

2.6 各種I/O模型的比較

這裡寫圖片描述
圖6:5種I/O模型的比較

從圖6可以看到,前四種I/O模型的主要區別在於第一個階段,它們的第二個階段是一樣的:在資料從核心複製到應用程序的緩衝區期間,程序會被阻塞於recvfrom系統呼叫。
而非同步I/O模型則是整個操作完成核心才通知應用程序。

三、同步I/O和非同步I/O

POSIX標準將同步I/O和非同步I/O定義為:

  • 同步I/O操作:導致請求程序阻塞,直到I/O操作完成。

  • 非同步I/O操作:不導致請求程序阻塞。

根據上述兩個定義,本文介紹的前面四種模型,包括阻塞式I/O,非阻塞式I/O,I/O複用和訊號驅動式I/O模型都是同步I/O模型,因為其中真正的I/O操作(recvfrom)將阻塞程序。只有非同步I/O模型才符合POSIX標準的非同步I/O定義。

四、生活中的類比例子

以生活中釣魚為例子(例子參考了參考資料2),來說明各種I/O模型的不同,例子中的等待魚上鉤對應於上文中的等待資料,拉竿操則作對應於上文的將資料從核心複製到使用者空間。

有A,B,C,D,E五個人在釣魚。
A使用了最古老的魚竿,所以開始釣魚後,就一直守著,直接魚上鉤了再拉竿;
B由於著急想知道有沒魚上鉤,所以隔一會就看一次魚竿看有沒魚上鉤,直到看到魚上鉤後,再拉竿;
C同時使用了N支魚竿來鉤魚,然後等著,只要有其中一支魚竿有魚上鉤,就將對應的魚竿拉起來;
D的魚竿比較高階,當有魚上鉤後,會發出警報提示,所以D開始釣魚後不用一直守著,一旦魚竿發出警報,D再回來拉竿即可;
E為了更省事,直接僱個傭人給他釣魚,當傭人釣起魚後,再通知E去取魚即可。

五、參考資料