【Linux】再談文件描述符之緩衝區

因爲IO相關函數與系統調用接口對應,並且庫函數封裝系統調用,所以本質上,訪問文件都是通過fd訪問的。所以C庫當中的FILE結構體內部,必定封裝了fd。

往標準輸出寫入有三種方法:

  • printf(str1);//C庫函數
  • fwrite(str2,1,strlen(str2),stdout);//C庫函數
  • write(1,str3,strlen(str3));//系統調用

來段代碼研究下:

運行出結果:

但是如果對進程實現輸出重定向呢?結果此時變成了:

 

我們發現 printf 和 fwrite (庫函數)都輸出了2次,而 write 只輸出了一次(系統調用)。爲什麼呢?肯定和fork有關!先來了解下緩衝區。

 

緩衝方式有三種

  • 無緩衝  (write)
  • 行緩衝(寫入顯示器):遇到 \n 或者緩衝區寫滿就刷新,執行真正的IO操作(printf)
  • 全緩衝(寫入硬盤):碰到1或者緩衝區寫滿才刷新(fwrite)
  • 一般C庫函數寫入文件時是全緩衝的,而寫入顯示器是行緩衝。
  • printf、fwrite 庫函數會自帶緩衝區(進度條例子就可以說明),當發生重定向到普通文件時,數據的緩衝方式由行緩衝變成了全緩衝。
  • 而我們放在緩衝區中的數據,就不會被立即刷新,甚至fork之後
  • 進程退出之後,會統一刷新,寫入文件當中。
  • 但是fork的時候,父子數據會發生寫時拷貝,所以當你父進程準備刷新的時候,子進程也就有了同樣的一份數據,隨即產生兩份數據。
  • write 沒有變化,說明沒有所謂的緩衝。

 此時再來說說爲什麼 printf 和 fwrite (庫函數)都輸出了2次,而 write 只輸出了一次(系統調用)?

解析:因爲在fork之前調用write,它的數據只寫到標準輸出一次,而它沒有緩衝區的概念,所以即使文件重定向到文件數據也是直接被輸出。fork出的子進程並沒有得到父進程的代碼數據。而printf和fwrite都是庫函數,他們自帶緩衝區,並且,重定向後行緩衝變爲全緩衝,即使遇到換行符也不輸出,直到緩衝區寫滿,此時fork便有了兩份數據。 

 

綜上: printf fwrite 庫函數會自帶緩衝區,而 write 系統調用沒有帶緩衝區。另外,我們這裏所說的緩衝區,
都是用戶級緩衝區。其實爲了提升整機性能,OS也會提供相關內核級緩衝區,不過不再我們討論範圍之內。
那這個緩衝區誰提供呢? printf fwrite 是庫函數, write 是系統調用,庫函數在系統調用的“上層”, 是對系統
調用的“封裝”,但是 write 沒有緩衝區,而 printf fwrite 有,足以說明,該緩衝區是二次加上的,又因爲是
C,所以由C標準庫提供。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章