欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Linux文件系統(tǒng)之緩沖區(qū)詳解

 更新時(shí)間:2024年02月25日 09:16:35   作者:春人.  
在 Linux 中,緩沖區(qū)通常指的是用于臨時(shí)存儲(chǔ)數(shù)據(jù)的內(nèi)存區(qū)域,它可以用來(lái)提高系統(tǒng)性能,Linux 中有多種類(lèi)型的緩沖區(qū),包括文件系統(tǒng)緩沖區(qū)、網(wǎng)絡(luò)緩沖區(qū)等,本文給大家詳細(xì)介紹了Linux文件系統(tǒng)之緩沖區(qū),感興趣的朋友可以參考下

一、先看現(xiàn)象

#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main()
{
    const char* fstr = "Hello fwrite\n";
    const char* str = "Hello write\n";

    printf("Hello printf\n");
    fprintf(stdout, "Hello fprintf\n");
    fwrite(fstr, strlen(fstr), 1, stdout); // 返回值是寫(xiě)入成功的快數(shù)

    write(1, str, strlen(str)); // 返回值是寫(xiě)入成功的字節(jié)數(shù)

    // fork();
    return 0;
}

在這里插入圖片描述

結(jié)構(gòu)分析:帶 fork 的輸出重定向最終把有一些內(nèi)容向 log.txt 文件中寫(xiě)入了多次,并且打印順序也有所不同。

int main()
{
    const char* fstr = "Hello fwrite";
    const char* str = "Hello write";

    printf("Hello printf");
    fprintf(stdout, "Hello fprintf");
    fwrite(fstr, strlen(fstr), 1, stdout); // 返回值是寫(xiě)入成功的快數(shù)

    close(1);

    // write(1, str, strlen(str)); // 返回值是寫(xiě)入成功的字節(jié)數(shù)

    // fork();
    return 0;
}

在這里插入圖片描述

結(jié)果分析:代碼中只使用了庫(kù)函數(shù)向顯示器中進(jìn)行寫(xiě)入,并且在字符串的結(jié)尾沒(méi)有加 \n,在最后面將標(biāo)準(zhǔn)輸出對(duì)應(yīng)的文件描述符進(jìn)行了關(guān)閉,最終顯示器上什么也沒(méi)有。上一段代碼在字符串的結(jié)尾加上了 \n 最終字符串被成功的打印到了屏幕上。

int main()
{
    const char* str = "Hello write";

    write(1, str, strlen(str)); // 返回值是寫(xiě)入成功的字節(jié)數(shù)
    close(1);
    
    return 0;
}

在這里插入圖片描述

結(jié)果分析:字符串的結(jié)尾依然不加 \n,但是這一次采用系統(tǒng)調(diào)用接口,最后仍然將標(biāo)準(zhǔn)輸出對(duì)應(yīng)的文件描述符進(jìn)行關(guān)閉,這一次字符串被成功的打印了出來(lái)。

二、用戶緩沖區(qū)的引入

write 為什么能將不帶 \n 的字符串寫(xiě)入到顯示器文件中。首先我們需要明確一點(diǎn)進(jìn)程打開(kāi)的每一個(gè)文件都有一個(gè)屬于自己的操作系統(tǒng)級(jí)別的文件緩沖區(qū),該緩沖區(qū)的存在,可以減少對(duì)外設(shè)的讀寫(xiě)操作以提高計(jì)算機(jī)的效率。舉個(gè)栗子,在一個(gè)進(jìn)程中向磁盤(pán)里的同一個(gè)文件進(jìn)多次行寫(xiě)入,文件緩沖區(qū)的存在,可以將每次寫(xiě)入的內(nèi)容先存儲(chǔ)在文件緩沖區(qū)中,最后在程序退出或者調(diào)用 close 的時(shí)候,一次性將文件緩沖區(qū)中的所有內(nèi)容刷新到磁盤(pán)。如果沒(méi)有該文件緩沖區(qū),那在進(jìn)程里對(duì)文件進(jìn)行 n 次寫(xiě)操做,就要對(duì)應(yīng) n 次向磁盤(pán)的寫(xiě)操作,CPU 和外設(shè)之間是存在非常大的速度差的,這樣效率會(huì)非常低。

write 作為系統(tǒng)調(diào)用接口,它就是直接向文件緩沖區(qū)中寫(xiě)入,最后在調(diào)用 close 接口或者程序退出的時(shí)候,會(huì)將文件緩沖區(qū)的內(nèi)容刷新到對(duì)應(yīng)的外設(shè)中。

printffprintf、fwrite 底層一定是封裝了 write 系統(tǒng)調(diào)用接口,那為什么使用 write 系統(tǒng)調(diào)用接口就可以將字符串寫(xiě)入到顯示器,使用 C 庫(kù)函數(shù)沒(méi)能把字符串寫(xiě)入到顯示器文件?原因在進(jìn)度條的那篇文章中講過(guò),我們使用的這些 C 庫(kù)函數(shù),是把字符串寫(xiě)入到了緩沖區(qū)中,這個(gè)緩沖區(qū)和上面的文件緩沖區(qū)有所不同,這里說(shuō)的緩沖區(qū)是 C 語(yǔ)言給我們提供的語(yǔ)言層面的緩沖區(qū),也叫做用戶級(jí)緩沖區(qū)\n 具有刷新用戶級(jí)緩沖區(qū)的作用,因此不加 \n 并且在程序結(jié)束前將顯示器對(duì)應(yīng)的文件描述符進(jìn)行了關(guān)閉,最終就導(dǎo)致字符串在用戶級(jí)緩沖區(qū)中,沒(méi)有被刷新到文件緩沖區(qū),所以屏幕上就什么也沒(méi)有。這里我們可以肯定,在這些 C 庫(kù)函數(shù)中,并不是立即調(diào)用 write 接口,而是在遇到 \n 后才去調(diào)用 write 接口將用戶緩沖區(qū)的內(nèi)容刷新到文件緩沖區(qū)中。

在這里插入圖片描述

總結(jié):使用 C 系統(tǒng)調(diào)用接口向文件中寫(xiě)入,寫(xiě)入的內(nèi)容先被存儲(chǔ)在用戶緩沖區(qū)中,在合適的時(shí)候(遇到 \n)才會(huì)進(jìn)行刷新,這里刷新的本質(zhì)是調(diào)用 write 將數(shù)據(jù)從用戶緩沖區(qū)寫(xiě)入內(nèi)核。

之前說(shuō)的 exit 會(huì)刷新緩沖區(qū),其實(shí)就是刷新用戶緩沖區(qū),因?yàn)?exit 作為 C 庫(kù)函數(shù),可以看見(jiàn)用戶緩沖區(qū),而 _exit 作為系統(tǒng)調(diào)用接口,無(wú)法看到語(yǔ)言層面的用戶緩沖區(qū),因此也就無(wú)法刷新用戶緩沖區(qū)。

三、用戶緩沖區(qū)的刷新策略

  • 無(wú)緩沖:直接刷新,數(shù)據(jù)不在用戶緩沖區(qū)中停留。
  • 行緩沖:不刷新,直到碰到 \n
  • 全緩沖:緩沖區(qū)滿了才刷新。

所謂刷新就是調(diào)用 write 接口將數(shù)據(jù)寫(xiě)入操作系統(tǒng)中的文件緩沖區(qū)。顯示器文件對(duì)應(yīng)采用的就是行緩沖,向磁盤(pán)文件中寫(xiě)入采用的是全緩沖。進(jìn)程在退出的時(shí)候也會(huì)刷新用戶緩沖區(qū),還可以調(diào)用 fflush 進(jìn)行刷新。

四、為什么要有用戶緩沖區(qū)

  • 解決效率問(wèn)題,緩沖區(qū)就像菜鳥(niǎo)驛站,不需要我們自己坐火車(chē)坐飛機(jī)去送東西,而是直接交給菜鳥(niǎo)驛站,然后就可以干自己的事情了,菜鳥(niǎo)驛站可以選擇攢上一大批快遞然后統(tǒng)一寄送出去。用戶緩沖區(qū)的存在本質(zhì)上提高了 C 語(yǔ)言的效率,也就是提高了用戶的效率,因?yàn)?C 語(yǔ)言是程序員在使用,在使用 C 庫(kù)函數(shù)進(jìn)行文件寫(xiě)入時(shí),大部分情況只需要把數(shù)據(jù)交給緩沖區(qū),然后就可以快速的返回,不需要每一次都親力親為的去和操作系統(tǒng)打交道。
  • 配合格式化,有些和文件寫(xiě)入相關(guān)的 C 庫(kù)函數(shù)是格式化輸出函數(shù),在我們看來(lái),它可以寫(xiě)入整形、符點(diǎn)型,但是最終都是以字符串的形式進(jìn)行寫(xiě)入。格式化就是將類(lèi)型全都轉(zhuǎn)化成字符串,先寫(xiě)入到用戶緩沖區(qū),用戶緩沖區(qū)中存的一定都是字符串。

用戶緩沖區(qū),有進(jìn)也有出,將數(shù)據(jù)寫(xiě)入到用戶緩沖區(qū)中就就叫做進(jìn),將用戶緩沖區(qū)中的數(shù)據(jù)刷新到內(nèi)核中的文件緩沖區(qū)中,被刷新的數(shù)據(jù)就可以從用戶緩沖區(qū)中刪掉,這就叫做出。用戶緩沖就像就像水流一樣源源不斷,流的概念就是因此而來(lái)。

小TipsFILE 里面就有對(duì)應(yīng)打開(kāi)文件的緩沖區(qū)字段和維護(hù)信息。每個(gè)被進(jìn)程打開(kāi)文件都有自己對(duì)應(yīng)的文件緩沖區(qū)。FILE 對(duì)象屬于用戶,用戶緩沖區(qū)可以看作是在堆上申請(qǐng)的一塊空間。

五、現(xiàn)象解釋

這下再來(lái)解釋上面代碼中有 fork 然后重定向,寫(xiě)入了多次的原因。首先重定向后,將本來(lái)向顯示器文件寫(xiě)入的內(nèi)容,寫(xiě)到了磁盤(pán)文件,顯示器文件的緩沖區(qū)采用行緩沖,即遇到 \n 就會(huì)刷新,而磁盤(pán)文件采用的是全緩沖,當(dāng)緩沖區(qū)滿了才刷新。因此在重定向后,會(huì)把三條 C 庫(kù)函數(shù)寫(xiě)入的內(nèi)容全部保存到緩沖區(qū)中,然后調(diào)用 fork 創(chuàng)建子進(jìn)程,此時(shí)父子進(jìn)程代碼共享,數(shù)據(jù)寫(xiě)時(shí)拷貝,在程序退出的時(shí)候回去刷新用戶緩沖區(qū),上面說(shuō)過(guò),刷新就是將用戶緩沖區(qū)中的數(shù)據(jù)寫(xiě)入到內(nèi)核,然后將用戶緩沖區(qū)中的內(nèi)容清空,上面還說(shuō)過(guò),緩沖區(qū)就是在堆上申請(qǐng)的一段空間,可以看作數(shù)據(jù)部分,因?yàn)橐獎(jiǎng)h除數(shù)據(jù),所以就會(huì)進(jìn)行寫(xiě)時(shí)拷貝,此時(shí)之前父進(jìn)程用戶緩沖區(qū)中的內(nèi)容就會(huì)給子進(jìn)程拷貝一份,然后父子進(jìn)程都執(zhí)行刷新動(dòng)作,各自刷新自己的緩沖區(qū)數(shù)據(jù),這就是為什么最終出現(xiàn)多份的原因。沒(méi)有重定向,只向顯示器打印四條消息,是因?yàn)轱@示器采用的是行刷新策略,在調(diào)用 fork 前,對(duì)應(yīng)的字符串就已經(jīng)被刷新出去了。在 fork 的時(shí)候,父進(jìn)程的用戶緩沖區(qū)中是空的,什么也沒(méi)有。

磁盤(pán)文件全緩沖驗(yàn)證

int main()
{
    const char* fstr = "Hello fwrite\n";
    const char* str = "Hello write\n";

    printf("Hello printf\n");
    sleep(2);
    fprintf(stdout, "Hello fprintf\n");
    sleep(2);
    fwrite(fstr, strlen(fstr), 1, stdout); // 返回值是寫(xiě)入成功的快數(shù)
    sleep(2);

    write(1, str, strlen(str)); // 返回值是寫(xiě)入成功的字節(jié)數(shù)

    sleep(5);

    fork();
    return 0;
}

在這里插入圖片描述

分析:最先將 write 內(nèi)容寫(xiě)入到文件中,因?yàn)樗侵苯訉?xiě)入到文件緩沖區(qū),而剩下的 C 庫(kù)函數(shù)對(duì)應(yīng)的內(nèi)容是統(tǒng)一一次全部刷新到內(nèi)核,即使每個(gè)字符串后面都有 \n,但最后還是統(tǒng)一全部刷新,這就證明了磁盤(pán)文件采用的是全刷新策略。

六、結(jié)語(yǔ)

以上就是Linux文件系統(tǒng)之緩沖區(qū)詳解的詳細(xì)內(nèi)容,更多關(guān)于Linux緩沖區(qū)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論