《深入理解計算機系統》 系統級I O

2021-06-18 18:15:55 字數 3640 閱讀 8612

關於i/o可以先參考這些文章,但是這裡可能還是有所不同。分析系統級別的i/o有什麼不一樣的地方。

檔案i/o

高階i/o

標準庫i/o

開篇介紹了三個級別的i/o的區別之處。所有語言的執行時系統都提供執行i/o的較高階別的工具。例如,標準i/o庫;在unix系統中,是通過使用由核心提供的系統級i/o函式來實現這些較高階別的i/o函式的。介紹unix i/o和標準i/o的一般概念,展示在c程式中如何可靠地使用它們。

在unix系統中有乙個說法,一切皆檔案。所有的i/o裝置,如網路、磁碟都被模型化為檔案,而所有的輸入和輸出都被當做對相應檔案的讀和寫來執行。這種將裝置對映為檔案的方式,允許unix核心引出乙個簡單、低階的應用介面,稱為unix i/o,這使得所有的輸入和輸出都能以一種統一且一致的方式來執行。

關於開啟檔案的基本操作,這裡就不再累述,就是關於幾個函式的解釋,在上面的三篇文章中有解釋。

在系統i/o中讀寫檔案用的系統函式為read()和write()函式來執行。

#include ssize_t read(int fd,void * buf,size_t n);

ssize_t write(int fd,void *buf,size_t n);

read函式從描述符為fd的當前檔案位置拷貝最多n個位元組到儲存器位置buf。返回值-1表示乙個錯誤,而返回值0表示eof。否則,返回值表示的是實際傳送的位元組數量。而write函式從儲存器位置buf拷貝至多n個位元組到描述符fd的當前檔案位置。返回值要麼為-1要麼為寫入的位元組數目。

/* $begin cpstdin */

int main(void)

/* $end cpstdin */

關於在檔案中定位使用的函式為lseek,在i/o庫中使用的函式為fseek。

(ps:size_t和ssize_t的區別,前者是unsigned int,而後者是int)

有些情況下,read和write傳送的位元組比應用程式要求的要少,出現這種情況的原因如下:

實際上,除了eof,在讀磁碟檔案時,將不會遇到不足值,而且在寫磁碟檔案時,也不會遇到不足值。然而,如果你想建立健壯的網路應用,就必須反覆呼叫read和write處理不足值,直到所有需要的位元組都傳送完畢。(這一點在unix網路程式設計中已經領略過了!!)

這個包會處理上面的不足,rio提供了方便、健壯和高效的i/o。提供了兩類不同的函式:

ssize_t rio_readn(int fd,void *usrbuf,size_t n);

ssize_t rio_writen(int fd,void *usrbuf,size_t n);

對同乙個描述符,可以任意交錯地呼叫rio_readn和rio_writen。乙個問本行的末尾都有乙個換行符,那麼像讀取乙個文字中的行數怎麼辦,使用read讀取換行符這個方法不是很妥當,可以呼叫乙個包裝函式(rio_readineb),它從乙個內部讀緩衝區拷貝乙個文字行,當緩衝區為空時,會自動地呼叫read重新填滿緩衝區。也就是說,這些函式都是緩衝區操作而言的。應用程式能夠通過呼叫stat和fstat函式檢索到關於檔案的資訊(有時也稱為檔案的元資料)

#include #include int stat(const char *filename,struct stat *buf);

int fstat(int fd,struct stat *buf);

若成功,返回0,若出錯則為-1.stat以乙個檔名為輸入,並且填充buf結構體。fstat函式只不過是以檔案描述符而不是檔名作為輸入。

struct stat ;
其中st_size成員包含了檔案的位元組大小。st_mode為檔案訪問許可位。unix提供的巨集指令根據st_mode成員來確定檔案的型別:s_isreg(),這是乙個普通檔案麼;s_isdir(),這是乙個目錄檔案麼;s_issock()這是乙個網路套接字麼。使用一下這個函式

#include #include #include #include #include #include int main()

下面看幾張圖。

描述符1和4通過不同的開啟檔案表表項來引用兩個不同的檔案。這是典型的情況,沒有共享檔案,並且每個描述符對應乙個不同的檔案。

多個描述符也可以通過不同的檔案表表項來應用同乙個檔案。如果同乙個檔案被open兩次,就會發生上面的情況。關鍵思想是每個描述符都有它自己的檔案位置,所以對不同描述符的讀操作可以從檔案的不同位置獲取資料。

父子程序也是可以共享檔案的,在呼叫fork()之前,父程序如第一張圖,然後呼叫fork()之後,子程序有乙個父程序描述符表的副本。父子程序共享相同的開啟檔案表集合,因此共享相同的檔案位置。乙個很重要的結果就是,在核心刪除相應檔案表表項之前,父子程序必須都關閉了他們的描述符。

標準i/o庫將乙個開啟的檔案模型化為乙個流。對於乙個程式而言,乙個流就是乙個指向file型別的結構的指標。型別為file的流是對檔案描述符和流緩衝區的抽象。流緩衝區的目的和rio讀緩衝區的一樣:就是使開銷較高的unix i/o系統呼叫的數量盡可能的小。例如,當第一次呼叫getc時,庫通過呼叫一次read函式來填充流緩衝區,然後將緩衝區總的第乙個位元組返回給應用程式。只要緩衝區還有未讀的位元組,接下來對getc的呼叫就能直接從流緩衝區得到服務。

上圖中展現了幾種i/o的關係模式,在應用程式中應該使用哪些函式呢?標準i/o函式是磁碟和終端裝置i/o的首選。但是對網路套接字上盡量使用健壯的rio或者系統i/o

26 深入理解計算機系統筆記,系統級I O

1 乙個 unix 檔案就是乙個 m位元組的序列 b0b1b2.bm 1 所有的 io裝置,如網路,磁碟,終端,都被模型化為檔案,而所有的輸入和輸出都被當作對相應檔案的讀和寫來執行。2 所有的輸入和輸出都被當作統一的方式來處理 1 開啟檔案。乙個應用程式通過要求核心開啟相應的檔案,來宣告它想要訪問乙...

26 深入理解計算機系統筆記,系統級I O

1 乙個 unix 檔案就是乙個 m位元組的序列 b0 b1b2 b m 1 所有的 io裝置,如網路,磁碟,終端,都被模型化為檔案,而所有的輸入和輸出都被當作對相應檔案的讀和寫來執行。2 所有的輸入和輸出都被當作統一的方式來處理 1 開啟檔案。乙個應用程式通過要求核心開啟相應的檔案,來宣告它想要訪...

深入理解計算機系統

關鍵路徑是在迴圈的反覆執行中形成的資料相關鏈。迴圈展開是一種程式變換,通過增加每次迭代計算的元素的數量,減少迴圈的迭代次數。重新結合變換能夠減少計算中關鍵路徑上操作的數量,通過更好地利用功能單元的流水線能力得到更好的效能。浮點運算不保證是可結合的,通常迴圈展開和並行地累積在多個值中,是提高程式效能的...