另一篇講得更好的
文章,裏面詳細講述了阻塞 非阻塞 同步 異步這幾個
阻塞I/O
非阻塞I/O
I/O複用(select和poll)
信號驅動I/O(SIGIO)
異步I/O(POSIX的aio_系列函數)
如下全部例子都使用recvfrom()函數來作講解。
阻塞I/O模型
在缺省狀況下,全部套接口都是阻塞的,進程調用recvfrom,其系統調用直到數據報到達且被拷貝到應用進程的緩衝區或者發生錯誤才返回。最多見的錯誤是系統調用被信號中斷。咱們說進程從調用recvfrom開始到它返回的整段時間內是被阻塞的,recvfrom成功返回後,進程開始處理數據報。
應用進程 內核
| recvfrom =========系統調用========> 無數據報準備好 ||
| || 等待
| || 數據
進程阻塞於 《 數據報準備好 ||
recvfrom的調用 | 拷貝數據報 ||
| || 將數據從內核
| || 拷貝到用戶空間
| 處理數據報 <========返回成功指示=======拷貝完成 ||
非阻塞I/O模型
進程把一個套接口設置成非阻塞是在通知內核:當所請求的I/O操做非得把本進程投入睡眠才能完成時,不要把本進程投入睡眠,而是返回一個錯誤。
當一個應用程序對一個非阻塞的描述字循環調用recvfrom是,咱們稱之爲輪詢(polling)。應用進程持續輪詢內核,以查看某個操做是否就緒。這麼作每每耗費大量CPU時間,不過這種模型不多會用到。
應用進程 內核
| recvfrom =========系統調用========> 無數據報準備好 |
| <====EWOULDBLOCK====== |
| recvfrom =========系統調用========> 無數據報準備好 |
等
| <====EWOULDBLOCK====== 》
| recvfrom =========系統調用========> 無數據報準備好 |
待
進程反覆調用
| <====EWOULDBLOCK====== |
數
recvfrom 等待 《
recvfrom =========系統調用========> 數據報準備好 |
據
返回成功 | 拷貝數據報 T
指示(輪詢) | || |
| ||
將數據從內核
| ||
拷貝到用戶空間
| || |
| 處理數據報 <========返回成功指示=========拷貝完成 |
I/O複用模型
有了I/O複用(I/O multiplexing),咱們就能夠調用select或poll,阻塞在這兩個系統調用中的某一個之上,而不是阻塞在真正的I/O系統調用上。
咱們阻塞於select調用,等待數據報套接口變爲可讀。當select返回套接口可讀這一條件時,咱們調用recvfrom把所讀數據報拷貝到應用進程緩衝區。
應用進程 內核
|| select =========系統調用========> 無數據報準備好 ||
進程受阻於select
| || |
調用,等待可能
| ||
多個套接口中的 《 》 等待數據
任一個變爲可讀
| ||
| || |
|| <=======返回可讀條件===== || ||
|| recvfrom =========系統調用=======> 數據報準備好 ||
| 拷貝數據報 |
數據拷貝到應用
| || |
緩衝區期間進程
《
》
將數據從內核
阻塞
| ||
拷貝到用戶空間
| || |
|| 處理數據報 <========返回成功指示========拷貝完成 ||
信號驅動I/O模型
咱們也能夠用信號,讓內核在描述字就緒時發送SIGIO信號通知咱們。咱們稱這種模型爲信號驅動I/O(signal-driven I/O)。
咱們首先開啓套接口的信號驅動I/O功能,並經過sigaction系統調用安裝一個信號處理函數。該系統調用當即發回,咱們的進程繼續工做,也就是說它沒有被阻塞。當數據報準備好時,內核就爲該進程產生一個SIGIO信號。咱們隨後既能夠在信號處理函數中調用recvfrom讀取數據報,並通知主循環數據已經準備好待處理,也能夠當即通知主循環,讓它讀取數據報。
不管如何處理SIGIO信號,這種模型的優點在於等待數據報到達期間,進程不被阻塞。主循環能夠繼續執行,只要不時等待來自信號處理函數的通知:既能夠是數據已經準備好被處理,也能夠是數據報已準備好被讀取。
應用進程 內核
創建SIGIO的 =========系統調用========> |
|| 信號處理程序 <==========返回========== |
| |
|
進程繼續執行 《 等待數據
| |
| |
||信號信號處理程序 <======遞交SIGIO====
數據報準備好
||
|| recvfrom ========系統調用======>
拷貝數據報
||
| || |
數據拷貝到應用
| || |
緩衝區期間進程
《
》
將數據從內核
阻塞
| ||
拷貝到用戶空間
| || |
|| 處理數據報 <========返回成功指示========拷貝完成 ||
異步I/O模型
異步I/O(asynchronous I/O)有POSIX規範定義。後來演變成當前POSIX規範的各類早期標準定義的實時函數中存在的差別已經取得一致。通常地說,這些函數的工做機制是:告知內核啓動某個操做,並讓內核在整個操做(包括將數據從內核拷貝到咱們本身的緩衝區)完成後通知咱們。這種模型與前與前面介紹的信號驅動模型的主要區別在於:信號驅動I/O是由內核通知咱們什麼時候能夠啓動一個I/O操做,而異步I/O模型是由內核通知咱們I/O操做什麼時候完成。
應用進程 內核
| aio_read =========系統調用========> 無數據報準備好 ||
| <=========返回========== ||
| 》 等待
數據
| ||
進程繼續執行 《 數據報準備好 ||
| 拷貝數據報 ||
| || 將數據從內核
| || 拷貝到用戶空間
| 處理數據報 <===遞交在aio_read中指定的信號===拷貝完成 ||
咱們調用aio_read函數(POSIX異步I/O函數以aio_或lio_開頭),給內核傳遞描述字、緩衝區指針、緩衝區大小(與read相同的三個參數)、文件偏移(與lseek相似),並告訴內核當整個操做完成時如何通知咱們。該系統調用當即返回,在等待I/O完成期間,咱們的進程不被阻塞。
各類I/O模型比較
==========================================================
|| 阻塞I/O || 非阻塞I/O || I/O複用 || 信號驅動I/O || 異步I/O ||
========================================================== +
|| 發起 || 檢查 || 檢查 || || 發起 || +
|| | || 檢查 || | || || || +
|| | || 檢查 || |
阻 || || || +
|| | || 檢查 || |
塞 || || || 等待
|| | || 檢查 || |
|| || || 數據
|| | || 檢查 || |
|| || || +
|| | || 檢查 || +
|| || || +
|| | 阻 || 檢查 || 就緒發起
|| 通知發起 || || =
|| | || 檢查 || |
|| | || || +
|| | 塞 || 檢查 || |
|| | || || +
|| | || 檢查 || |
阻 || | 阻 || ||
將數據
|| | || | || |
塞 || |
塞 || ||
從內核
|| | || | || |
|| | || ||
拷貝到
|| | || | || |
|| | || ||
用戶空間
|| + || + || +
|| + || || +
|| 完成 || 完成 || 完成 || 完成 || 通知 || +
==========================================================
-------------------------------------------------------------------------------------------- -------------------
第一階段處理不一樣 處理兩個階段
第二階段處理不一樣
(阻塞於recvfrom調用)
同步I/O與異步I/O
POSIX把這兩個術語定義以下:
·同步I/O操做(synchronous I/O operation)致使請求進程阻塞,直到I/O操做完成。
·異步I/O(asynchronous I/O operation)不致使請求進程阻塞。
根據上述定義,咱們前4種模型----阻塞I/O模型、非阻塞I/O模型、I/O複用模型和信號去驅動I/O模型都是同步I/O模型,由於其中真正的I/O操做(recvfrom)將阻塞進程。
只有異步I/O模型與POSIX定義的異步I/O相匹配。