1. 程式人生 > >同步、非同步與阻塞、非阻塞

同步、非同步與阻塞、非阻塞

UNIX下可用的I/O模型:

  • 阻塞式I/O;
  • 非阻塞式I/O;
  • I/O複用(select,poll,epoll…);
  • 訊號驅動式I/O(SIGIO);
  • 非同步I/O(POSIX的aio_系列函式);

阻塞式I/O模型:預設情況下,所有套接字都是阻塞的。

一個輸入操作通常包括兩個不同階段:(1)等待資料準備好;(2)從核心向程序複製資料。

對於一個套接字上的輸入操作,第一步通常涉及等待資料從網路中到達。當所有等待分組到達時,它被複制到核心中的某個緩衝區。第二步就是把資料從核心緩衝區複製到應用程式緩衝區。
我們以阻塞套接字的recvfrom的呼叫圖來說明阻塞

在這裡插入圖片描述

標紅的這部分過程就是阻塞,直到阻塞結束recvfrom才能返回。

非阻塞式I/O

以下這句話很重要:程序把一個套接字設定成非阻塞是在通知核心,當所請求的I/O操作非得把本程序投入睡眠才能完成時,不要把程序投入睡眠,而是返回一個錯誤。

看看非阻塞的套接字的recvfrom操作如何進行
在這裡插入圖片描述
可以看出recvfrom總是立即返回

I/O多路複用:

雖然I/O多路複用的函式也是阻塞的,但是其與以上兩種還是有不同的,I/O多路複用是阻塞在select,epoll這樣的系統呼叫之上,而沒有阻塞在真正的I/O系統呼叫如recvfrom之上。
如圖
在這裡插入圖片描述

訊號驅動式I/O

用的很少,就不做講解了。直接上圖
在這裡插入圖片描述

非同步I/O

這類函式的工作機制是告知核心啟動某個操作,並讓核心在整個操作(包括將資料從核心拷貝到使用者空間)完成後通知我們。如圖
在這裡插入圖片描述
注意紅線標記處說明在呼叫時就可以立馬返回,等函式操作完成會通知我們。

前四種I/O模型都是同步I/O操作,他們的區別在於第一階段,而他們的第二階段是一樣的:在資料從核心複製到應用緩衝區期間(使用者空間),程序阻塞於recvfrom呼叫。
相反,非同步I/O模型在這兩個階段都要處理。
在這裡插入圖片描述

POSIX對這兩個術語的定義:
同步I/O操作:導致請求程序阻塞,直到I/O操作完成;
非同步I/O操作:不導致請求程序阻塞。

小結

阻塞,非阻塞: 程序/執行緒要訪問的資料是否就緒,程序/執行緒是否需要等待;

同步,非同步: 訪問資料的方式,同步需要主動讀寫資料,在讀寫資料的過程中還是會阻塞;非同步只需要I/O操作完成的通知,並不主動讀寫資料,由作業系統核心完成資料的讀寫。

理解(知乎)

“阻塞”與"非阻塞"與"同步"與“非同步"不能簡單的從字面理解,提供一個從分散式系統角度的回答。

1.同步與非同步同步和非同步關注的是訊息通訊機制 (synchronous communication/ asynchronous communication)所謂同步,就是在發出一個呼叫時,在沒有得到結果之前,該呼叫就不返回。但是一旦呼叫返回,就得到返回值了。換句話說,就是由呼叫者主動等待這個呼叫的結果。
而非同步則是相反,呼叫在發出之後,這個呼叫就直接返回了,所以沒有返回結果。換句話說,當一個非同步過程呼叫發出後,呼叫者不會立刻得到結果。而是在呼叫發出後,被呼叫者通過狀態、通知來通知呼叫者,或通過回撥函式處理這個呼叫。

舉個通俗的例子:你打電話問書店老闆有沒有《分散式系統》這本書,如果是同步通訊機制,書店老闆會說,你稍等,”我查一下",然後開始查啊查,等查好了(可能是5秒,也可能是一天)告訴你結果(返回結果)。而非同步通訊機制,書店老闆直接告訴你我查一下啊,查好了打電話給你,然後直接掛電話了(不返回結果)。然後查好了,他會主動打電話給你。在這裡老闆通過“回電”這種方式來回調。

2.阻塞與非阻塞阻塞和非阻塞關注的是程式在等待呼叫結果(訊息,返回值)時的狀態.
阻塞呼叫是指呼叫結果返回之前,當前執行緒會被掛起。呼叫執行緒只有在得到結果之後才會返回。
非阻塞呼叫指在不能立刻得到結果之前,該呼叫不會阻塞當前執行緒。

還是上面的例子,你打電話問書店老闆有沒有《分散式系統》這本書,你如果是阻塞式呼叫,你會一直把自己“掛起”,直到得到這本書有沒有的結果,如果是非阻塞式呼叫,你不管老闆有沒有告訴你,你自己先一邊去玩了, 當然你也要偶爾過幾分鐘check一下老闆有沒有返回結果。在這裡阻塞與非阻塞與是否同步非同步無關。跟老闆通過什麼方式回答你結果無關。