Linux IO模型簡述

在Linux中,爲了操作系統的安全性等,進程無法直接操作IO設備,必須通過系統調用來請求內核協助完成IO動作,內核會爲每個IO設備維護一個buffer。當用戶發起請求後,內核接收到請求,從IO設備中獲取數據到buffer中,再將buffer中的數據拷貝到用戶進程的地址空間,用戶進程獲取到數據後在響應客戶端。這個過程可以分成兩個階段:

1.等待數據準備

2.將數據從內核拷貝到進程中

根據這兩個階段等待方式的不同,IO動作可以分爲以下五種模式

阻塞IO

在Linux中,默認情況下所有的socket都是阻塞的。以recvfrom調用爲例,當用戶進程調用了recvfrom系統調用時,數據可能還沒有到達,此時爲IO的第一個階段:等待數據準備。此時用戶進程會被阻塞。當數據準備好後,進入IO的第二個階段:將數據從內核拷貝到進程中。當拷貝完成後,內核返回結果,用戶進程解除阻塞狀態,繼續運行。

在IO執行的兩個階段,用戶進程都處於阻塞狀態,在等待數據返回的過程中不能進行其他的操作。

非阻塞IO

通過設置socket可使其變爲非阻塞的。非阻塞的recvfrom調用後,內核不會阻塞用戶進程,如果數據還未準備好,會立刻返回一個EWOULDBLOCK或EAGAIN錯誤,進程接收到返回後,可以進行其他操作,然後用戶進行再次發起recvfrom調用。直到數據準備好,並再次收到用戶進程的系統調用,將數據拷貝到用戶進程中,當拷貝完成後,內核返回結果。

在IO執行的第一個階段不是完全阻塞的,第二個階段是阻塞的。第一階段通過輪詢的方式確認數據是否準備好,通常會浪費cpu時間。

IO多路複用

當用戶進程調用了select,進程會被阻塞,此時,內核會“監視”select負責的所有socket,當任何一個socket中的數據準備好了,select就會返回,此時用戶進程再調用read操作,將數據從內核拷貝到用戶進程中。

IO多路複用的優勢是單個進程就可以同時處理多個網絡連接的IO,節約系統資源。兩個階段用戶進程都是阻塞狀態,第一階段是阻塞在select,而不是IO操作。

信號驅動的IO

用戶進程建立SIGIO信號處理程序,通過調用系統調用sigaction執行一個信號處理函數,然後用戶進程就可以進行其他操作。當數據準備好後,用戶進程會收到一個SIGIO信號,通知用戶進程數據已準備好,然後用戶進程調用recvfrom將數據從內核拷貝到用戶進程中。

信號驅動的IO在第一階段是非阻塞的,第二階段是阻塞的。

異步IO

當用戶進程調用了aio_read後,無論數據是否準備好,都會返回,不會對用戶進程造成阻塞。當數據準備好後,內核直接將數據拷貝到用戶進程中,拷貝完成後,內核向用戶進程發送調用aio_read時指定的信號。用戶進程收到信號後,對數據進行處理。

異步IO在IO操作的兩個階段都是非阻塞的。與信號驅動的IO不同在於,當用戶進程接收到信號時,數據已經完成拷貝,直接處理數據即可。

對比

前四種模型的主要區別在於IO操作第一階段的處理不同,第二階段都是阻塞的。最後一種模型兩個階段都是非阻塞的。

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