目錄
一、問題引入
二、緩沖區(qū)
1、什么是緩沖區(qū)
2、刷新策略
3、緩沖區(qū)由誰提供
4、重看問題
三、緩沖區(qū)的簡(jiǎn)單實(shí)現(xiàn)
一、問題引入
我們先來看看下面的代碼:我們使用了C語言接口和系統(tǒng)調(diào)用接口來進(jìn)行文件操作。在代碼的最后,我們還使用fork函數(shù)創(chuàng)建了一個(gè)子進(jìn)程。
?代碼運(yùn)行結(jié)果如下:
結(jié)果沒有什么問題啊?結(jié)果很正確。但是我們?cè)賮砜纯聪旅娴牟僮鳎何覀儗?duì)其進(jìn)行輸出重定向。然后,查看log.txt的代碼。
我們驚奇地發(fā)現(xiàn),文件里面的內(nèi)容和打印到顯示器的內(nèi)容是不一樣的!我們?cè)僮屑?xì)觀察,發(fā)現(xiàn),C語言的函數(shù)都打印了兩次,而系統(tǒng)調(diào)用接口只打印了一次。為什么呢??
這種現(xiàn)象就和fork函數(shù)以及我們下面要講的緩沖區(qū)有關(guān)了。
二、緩沖區(qū)
1、什么是緩沖區(qū)
緩沖區(qū)的本質(zhì)就是一段內(nèi)存空間。
我們知道,內(nèi)存的速度比磁盤的速度快了幾個(gè)數(shù)量級(jí)。所以數(shù)據(jù)如果直接從內(nèi)存寫到磁盤,那么訪問外設(shè)效率比較低,那就太消耗時(shí)間了。所以緩沖區(qū)的意義就是通過減少與外設(shè)的IO次數(shù),來節(jié)省進(jìn)程進(jìn)行數(shù)據(jù)IO的時(shí)間。
所以C語言中就提供了緩沖區(qū)。而有了緩沖區(qū)的存在,可以提高整機(jī)效率,并提高用戶的響應(yīng)速度。
2、刷新策略
~ 立即刷新。
~ 行刷新(行緩沖)。(常見的對(duì)顯示器進(jìn)行數(shù)據(jù)刷新)以\n為標(biāo)志
~ 滿刷新(全緩沖)。(常見的對(duì)磁盤文件寫入數(shù)據(jù))
特殊情況:1、用戶強(qiáng)制刷新(fflush)? ? ? ? ? 2、進(jìn)程退出
注:所有的設(shè)備,永遠(yuǎn)都傾向于全緩沖,即緩沖區(qū)滿了才刷新,因?yàn)檫@樣只需要更少的IO操作,更少次的外設(shè)訪問,效率更高。
當(dāng)然,我們要根據(jù)實(shí)際情況去改變刷新策略。如:顯示器是直接給用戶看的,一方面要照顧效率,一方面要照顧用戶體驗(yàn)。所以顯示器一般使用行刷新。
3、緩沖區(qū)由誰提供
從上面的例子,我們發(fā)現(xiàn)直接往顯示器上打印的結(jié)果為4條,往文件打印的結(jié)果為7條,這跟緩沖區(qū)有關(guān),同時(shí)這也說明了緩沖區(qū)一定不在Linux內(nèi)核中,為什么?因?yàn)閣rite是系統(tǒng)接口,如果在內(nèi)核中,write也應(yīng)該打印兩次。所以緩沖區(qū)是由C標(biāo)準(zhǔn)庫提供的。
我們之前所說的所有緩沖區(qū)都指的是用戶級(jí)語言層面提供的緩沖區(qū)。stdout,stdin,stderr對(duì)應(yīng)的類型——FILE*,F(xiàn)ILE是一個(gè)結(jié)構(gòu)體,里面封裝了fd,同時(shí)還包括了一個(gè)緩沖區(qū)。
從源碼出發(fā),我們可以來看一看FILE結(jié)構(gòu)體:
4、重看問題
有了緩沖區(qū)的概念,我們就來解釋解釋問題引入中的現(xiàn)象。
首先,我們要先知道,代碼運(yùn)行完了,并不代表數(shù)據(jù)已經(jīng)刷新了。上面代碼中,使用C語言函數(shù)的操作在執(zhí)行完了后,先將數(shù)據(jù)寫入了緩沖區(qū)中,并沒有直接向顯示器上打印。
第一次運(yùn)行,沒有重定向操作,就是直接向顯示器打印,而顯示器的刷新策略是行刷新,且每個(gè)代碼后面都有\(zhòng)n,所以在調(diào)用fork之前,代碼不僅執(zhí)行完了,而且數(shù)據(jù)都已經(jīng)刷新了。所以fork對(duì)結(jié)果沒有影響。
第二次運(yùn)行,我們有了重定向操作,于是函數(shù)就由向顯示器打印變成了向磁盤文件打印。所以刷新策略也由行刷新變成了滿刷新。那么\n就已經(jīng)沒有意義了。所以代碼在運(yùn)行到fork時(shí),之前的代碼雖然已經(jīng)運(yùn)行完成了,但是數(shù)據(jù)還沒有刷新到文件中。數(shù)據(jù)還在當(dāng)前進(jìn)程對(duì)應(yīng)的C標(biāo)準(zhǔn)庫中的緩沖區(qū)中,且該數(shù)據(jù)屬于父進(jìn)程。
于是最后,我們fork創(chuàng)建了子進(jìn)程。接著,父進(jìn)程或子進(jìn)程退出,這時(shí)數(shù)據(jù)會(huì)強(qiáng)制刷新出來。我們假設(shè)父進(jìn)程先退出:父進(jìn)程退出后,其數(shù)據(jù)強(qiáng)制刷新,而刷新的過程也是一種寫入,所以這時(shí),為了父子進(jìn)程的數(shù)據(jù)不會(huì)相互影響,就會(huì)發(fā)生寫時(shí)拷貝!這樣數(shù)據(jù)就會(huì)有兩份,于是父子進(jìn)程各自退出時(shí)都會(huì)刷新各自的數(shù)據(jù)。(當(dāng)然,如果子進(jìn)程先退出也是同樣的)
所以,簡(jiǎn)單總結(jié)來說:重定向?qū)е滤⑿虏呗园l(fā)生了改變(由行緩沖變成了全緩沖)。同時(shí)發(fā)生了寫時(shí)拷貝,父子進(jìn)程各自刷新。
三、緩沖區(qū)的簡(jiǎn)單實(shí)現(xiàn)
有了緩沖區(qū)的一些基本概念。我們可以自己實(shí)現(xiàn)一個(gè)簡(jiǎn)單的帶有緩沖區(qū)的struct file。
主函數(shù):
int main
{
MyFILE* fp = fopen_("log.txt", "r");
if(fp==NULL)
{
printf("open file fail");
return 0;
}
fputs_("hello world", fp);
fclose_(fp);
return 0;
}
struct file
struct MyFILE_
{
int fd;
char buff[NUM];
int end;//當(dāng)前緩沖區(qū)的結(jié)尾
};
typedef struct MyFILE_ MyFILE;
?fopen函數(shù)的簡(jiǎn)單實(shí)現(xiàn)
MyFILE* fopen_(const char* pathname, const char* mode)
{
assert(pathname);
assert(mode);
MyFILE* fp = NULL;
if(strcmp(mode, "w")==0)
{
int fd = open(pathname, O_WRONLY|O_TRUNC|O_CREAT);
if(fd>0)
{
MyFILE* fp=(MyFILE*)malloc(sizeof(MyFILE));
memset(fp,'\0',sizeof(MyFILE));
fp->fd = fd;
}
}
else if(strcmp(mode, "w+")==0)
{}
else if(strcmp(mode,"r")==0)
{}
else if(strcmp(mode,"r+")==0)
{}
else if(strcmp(mode,"a")==0)
{}
else if(strcmp(mode,"a+")==0)
{}
else
{}
return fp;
}
fputs函數(shù)的簡(jiǎn)單實(shí)現(xiàn)文章來源:http://www.zghlxwxcb.cn/news/detail-769680.html
void fputs_(const char* message, MyFILE* fp)
{
assert(message);
assert(fp);
strcpy(fp->buff+fp->end, message);
fp->end += strlen(message);
if(fp->fd==0)
{}
else if(fp->fd==1)
{
if(fp->buff[fp->end-1]== '\n')
{
write(fp->fd, fp->buff,fp->end);
fp->end = 0;
}
}
else if(fp->fd==2)
{}
else
{}
}
fclose函數(shù)簡(jiǎn)單實(shí)現(xiàn)和fflush函數(shù)文章來源地址http://www.zghlxwxcb.cn/news/detail-769680.html
void fclose_(MyFILE* fp)
{
assert(fp);
fflush_(fp);
close(fp->fd);
free(fp);
}
void fflush_(MyFILE* fp)
{
assert(fp);
if(fp->end != 0)
{
write(fp->fd, fp->buff, fp->end);
syncfs(fp->fd);
fp-> end = 0;
}
}
到了這里,關(guān)于Linux之緩沖區(qū)的理解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!