天天看點

了解阻塞I/O和非阻塞I/O,同步I/O和異步I/O

首先需要明确一下系統調用的概念:當運作在使用者空間的程式需要向核心請求更高權限的服務時,需要進行系統調用,它提供作業系統和使用者程式之間的接口,類似于普通庫函數,但是由作業系統核心提供并運作于核心态,而普通庫函數由函數庫或使用者自己提供并運作于使用者态。是以,進行系統調用時會經曆從使用者态轉到核心态運作一段時間,然後再轉回到使用者态的過程。

阻塞I/O和非阻塞I/O

阻塞I/O:系統調用會被作業系統挂起,直至等待的事件發生位置。

非阻塞I/O:系統調用會立刻傳回,不管事件有沒有發生。若事件沒有發生或出錯,均傳回-1,并設定相應的errno。然後,每隔一段時間再調用系統函數,檢視事件有沒有發生。

是以,阻塞I/O與非阻塞I/O的主要差別就是系統調用是否立即傳回。

同步I/O和異步I/O

同步I/O:使用者等待事件發生或者不斷地查詢事件是否發生,事件發生後,I/O通知使用者去執行I/O操作。這裡I/O操作是指将資料從核心緩沖區讀入使用者緩沖區,或将資料從使用者緩沖區寫入核心緩沖區。

異步I/O:使用者可以直接對I/O執行讀寫操作,告訴核心使用者讀寫緩沖區的位置以及I/O操作完成後核心通知應用程式的方式,然後在事件發生後,核心會根據這些資訊執行I/O操作。最後,I/O直接通知使用者I/O完成。

是以,同步I/O和異步I/O的主要差別就是I/O操作由誰執行。

五種I/O模型

這裡讨論的五種I/O模型分别是:阻塞I/O模型、非阻塞I/O模型、I/O複用模型、信号驅動I/O模型以及異步I/O模型,其中,前面四種均是同步I/O。

下面使用Linux下的系統調用recv作為例子來分别讨論這五種模型,recv用于從套接字上接收一個消息。

阻塞I/O模型

使用recv的預設參數一直等資料直到拷貝到使用者空間,這段時間内程序始終阻塞。

了解阻塞I/O和非阻塞I/O,同步I/O和異步I/O

非阻塞I/O模型

改變flags,讓recv不管有沒有擷取到資料都傳回,如果沒有資料那麼一段時間後再調用recv看看,如此循環。

了解阻塞I/O和非阻塞I/O,同步I/O和異步I/O

I/O複用模型

這裡在調用recv前先調用select或者poll,這2個系統調用都可以在核心準備好資料(網絡資料到達核心)時告知使用者程序,這個時候再調用recv一定是有資料的。是以這一過程中它是阻塞于select或poll,而沒有阻塞于recv,有人将非阻塞IO定義成在讀寫操作時沒有阻塞于系統調用的IO操作(不包括資料從核心複制到使用者空間時的阻塞,因為這相對于網絡IO來說确實很短暫)。這種IO模型比較特别,分個段。因為它能同時監聽多個檔案描述符(fd)。

了解阻塞I/O和非阻塞I/O,同步I/O和異步I/O

信号驅動I/O模型

通過調用sigaction注冊信号函數,等核心資料準備好的時候系統中斷目前程式,執行信号函數(在這裡面調用recv)。

了解阻塞I/O和非阻塞I/O,同步I/O和異步I/O

異步I/O模型

調用aio_read,讓核心等資料準備好,并且複制到使用者程序空間後執行事先指定好的函數。

了解阻塞I/O和非阻塞I/O,同步I/O和異步I/O

繼續閱讀