Nonblocking and Asynchronous I/O
Basic Concept
I/O device 的實際動作通常是 asynchronous 的:disk、network、keyboard 都不會保證在 CPU 要求的那一瞬間立刻完成。但 OS 對 application 提供的 system call 可以設計成 blocking、nonblocking、或 asynchronous
這三者都在處理同一個問題:I/O 很慢或不可預測,application 要不要停下來等?
Blocking I/O
Blocking I/O 是最直覺的模型。Application 呼叫 read() 或 write() 後,如果資料還沒 ready,calling thread 會被 OS suspend:
- Thread 發出 I/O system call。
- Kernel 發現 I/O 不能立即完成。
- Thread 從 run queue 移到 wait queue。
- Device 完成 I/O 後,interrupt handler / kernel I/O subsystem 喚醒 thread。
- Thread 回到 ready queue,之後被 scheduler 選上 CPU 才繼續執行。
Blocking I/O 容易寫,因為程式碼看起來像順序執行;但缺點是 thread 在等待 I/O 期間不能做其他工作。
Nonblocking I/O
Nonblocking I/O 的 system call 不會讓 thread 長時間睡眠。它會立即回傳,並告訴 application 目前能完成多少 I/O。
以 nonblocking read() 為例:
- 如果 requested bytes 都 available,就回傳全部。
- 如果只有部分 data available,就回傳部分 bytes。
- 如果完全沒有 data available,就立即回傳「目前沒有資料」的結果。
Nonblocking I/O 適合不想被單一 I/O request 卡住的程式,例如 GUI 程式同時要處理 keyboard/mouse input 和畫面更新。
Asynchronous I/O
Asynchronous I/O 比 nonblocking I/O 更進一步。Application 發出 request 後 system call 立即回傳,但這個 request 不是只問「現在有多少資料」,而是要求 OS 在未來完整完成一個 I/O operation。完成時,OS 會用某種方式通知 application
也就是說,asynchronous I/O 把「發出 request」和「取得 completion」拆成兩個時間點。
Nonblocking vs Asynchronous
| Type | system call 回傳時 I/O 狀態 | application 拿到什麼 |
|---|---|---|
| Blocking I/O | I/O 已完成 | 完整結果或 error |
| Nonblocking I/O | 不一定完成,只回報目前可做多少 | 目前 available 的資料量 |
| Asynchronous I/O | 尚未完成也可以回傳 | 未來透過 notification 得知 completion |
關鍵差異是:nonblocking read 是「現在有多少給多少」;asynchronous read 是「這個完整 request 之後完成再通知我」。