14.1 引言
*進階I/O包括非阻塞I/O、記錄鎖、系統V流機制、I/O多路轉換(select和poll函數)、readv和writev函數以及儲存映射I/O(mmap)
14.2 非阻塞I/O
*非阻塞I/O使我們可以調用open、read和write這樣的I/O操作,並使這些操作不會永遠阻塞
14.3 記錄鎖
*記錄鎖(record locking)的功能是:當一個進程正在讀或修改檔案的某個部分時,它可以組織其他進程修改同一檔案區
*考慮資料庫訪問常式庫。如果該庫中所以函數都以一致的方法處理記錄鎖,則稱使用這些函數訪問資料庫的任何進程集為合作進程(cooperating process)。
*建議性鎖並不能阻止對資料庫檔案有寫入權限的任何其他進程對資料庫檔案進行隨意的寫操作
*強制性鎖使核心對每一個open、read和write系統調用都進行檢查,檢查調用進程對正在訪問的檔案是否違背了某一把鎖的作用。強制性鎖有時也被稱為強迫方式鎖(enforcement-mode locking)
*如果一個進程試圖讀、寫一個強制性鎖起作用的檔案,而欲讀、寫的部分又由其他進程加上了讀或寫鎖,此時會發生什麼呢?對這一問題的回答取決於三方面的因素:操作類型(read或write),其他進程保有的鎖的類型(讀鎖或寫鎖),以及有關描述符是阻塞還是非阻塞的
14.4 STREAMS
*流在使用者進程和裝置驅動程式之間提供了一條全雙工系統通路。流無需和實際硬體會話,流也可以用來構造偽裝置驅動程式
*任意數量的處理模組可以壓入流。我們使用術語壓入,是因為每一新模組總是插到流首之下,而將以前的模組下壓(這類似於後進先出的棧)
*ioctl的第二個參數request說明執行哪一個操作。所有request都以I_開始。第三個參數的作用與request有關,有時它是一個整數值,有時它是指向一個整型或一個資料結構的指標
14.5 I/O多路轉接
*問題:telnet進程有兩個輸入、兩個輸出。對這兩個輸入中的任一個都不能使用阻塞read,因為我們永遠不知道哪一個輸入有我們需要的資料
*一種方法是仍舊使用一個進程執行該程式,但使用非阻塞I/O讀取資料。基本方法是將兩個輸入描述符都設定為非阻塞的,對第一個描述符發一個read。如果該輸入上有資料,則讀資料並處理它;如果無資料可讀,則read立即返回。然後對第二個描述符作同樣的處理。
*一種比較好的技術是I/O多路轉換(I/O multiplexing)。先構造一張有關描述符的列表,然後調用一個函數,直到這些描述符中的一個已準備好進行I/O時,該函數才返回。在返回時,它告訴進程哪些描述符已準備好可以進行I/O
14.6 非同步I/O
*除了調用ioctl說明產生SIGPOLL訊號的條件以外,還應為該訊號建立訊號處理常式。對於SIGPOLL的預設動作是終止該進程,所以應當在調用ioctl之前建立訊號處理常式
14.7 readv和writev函數
*readv和writev函數用於在一次函數調用中讀、寫多個非連續緩衝區。有時也將這兩個函數稱為散布讀(scatter read)和聚集寫(gather write)
14.8 readn和writen函數
*管道、FIFO以及某些裝置,特別是終端、網路和STREAMS裝置有下列兩種性質:
(1)一次read操作所返回的資料可能少於所要求的資料,即使還沒達到檔案尾端也可能是這樣。這不是一個錯誤,應當繼續改裝置
(2)一次write操作的傳回值也可能少於指定的位元組
14.9 儲存映射I/O
*儲存映射I/O(Memory-mapped I/O)使一個磁碟檔案與儲存空間中的一個緩衝區相映射
*mmap函數實現就告訴核心將一個檔案對應到一個儲存地區中
*void *mmap(void *addr, size_t len, int prot, int flag, int filedes, off_t off);
*addr參數用於指定映射儲存區的起始地址
*len是映射位元組數
*prot參數說明對映射儲存區的保護要求。對指定映射儲存區的保護要求不能超過檔案open模式存取權限
*flag參數影響映射儲存區的多種屬性
*filedes指定要被對應檔的描述符
*off是要映射位元組在檔案中的起始位移量