天天看點

LINUX系統程式設計 關于SDTIO庫緩沖區

我們知道标準C中的檔案讀取的函數比如printf,fwrite等函數,實際都是調用OS級别的

API,比如LINUX下就是wirte,read函數,而write read函數在使用者态下是沒有緩沖的,

當然在核心态有OS CACHE/OS BUFFER,是以某些直接調用wirte,read的程式肯定會

配置設定一個緩沖區,特别是O_DIRECT這種方式下,核心态的OS CACHE和OS BUFFER沒用

這種情況下使用者态的BUFFER顯得更加重要,因為不可能一次讀一個位元組吧,那性能可想而知

而作為使用者态空間的STDIO也是這樣做的,它會為打開的檔案配置設定緩存,預設應該是8192位元組

如下圖摘自UNIX系統程式設計手冊 13章:

LINUX系統程式設計 關于SDTIO庫緩沖區

實際上我們可以使用setvbuf來設定某個打開檔案的緩沖大小及模式。

我們來看看原型:

int setvbuf(FILE *stream, char *buf, int mode, size_t size);

傳回0為成功,非零為失敗

FILE *stream:打開檔案的FILE*

char *buf:BUFFER的位址,如果為NULL,MODE為_IOLBF和_IOFBF則自動配置設定緩沖區

           如果為_IONBF則不配置設定緩沖區

int mode:_IONBF不使用緩沖區,立即調用write/read,忽略buf和size為NULL和0,stderr屬于這個

          _IOLBF使用行緩沖I/O,終端裝置預設為這種。要麼遇到換行符要麼緩沖滿才調用write/read,

          stdin/stdout屬于這個。

          _IOFBF采用全緩沖I/O,buffer滿才調用write/read,磁盤I/O屬于這個比如fwrite/fread

size_t size:緩沖大小

更簡單函數setbuf原型如下:

void setbuf(FILE *stream, char *buf);

相當于

setvbuf(fp,buf,(buf !=NULL)?_IOFBF:_IONBF,BUFSIZ);

如果buf=NULL則_IONBF打開不帶緩沖,或者調用全緩沖,BUFSIZ預設8192。

是以我們如果不想用緩沖直接:

setvbuf(fp,NULL)

即可。

現在回想一下fread

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

fread的時候我們通常要calloc一塊記憶體用于void *ptr,那麼現在我們想一下實際

上這個資料正常緩存到了3個地方

1、使用者配置設定的記憶體*ptr

2、STDIO的緩存預設8192

3、核心态OS CACHE

這視乎有點臃腫,我們可以想辦法簡化。事實上資料庫軟體有時候隻使用了使用者态

的一份緩存,而打開O_DIRECT來提高性能。

下面一個小程式可以驗證打開和關閉stdout緩沖的差別:

int main(void)

{

        int i;

//      setbuf(stdout,NULL);

        for(i=0;i<10;i++)

        {

                printf("-");

                sleep(1);

        }

        printf("\n");

}

差別就是是否使用setbuf,如果使用setbuf則 -符号會一個一個輸出,不使用會一起輸出

這就是STDIO緩存在作怪。