Linux——緩沖區

一、問題引入

我們先來看看下面的代碼:我們使用了C語言接口和系統調用接口來進行文件操作。在代碼的最后,我們還使用fork函數創建了一個子進程。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<string.h>int main()
{fprintf(stdout,"hello fprintf\n");const char*s="hello fputs\n";fputs(s,stdout);printf("hello printf\n");const char* ss="hello write\n";write(1,ss,strlen(ss));frok();return 0;
}

代碼運行結果如下:

結果沒有什么問題啊?結果很正確。但是我們再來看看下面的操作:我們對其進行輸出重定向。然后,查看log.txt的代碼。

我們驚奇地發現,文件里面的內容和打印到顯示器的內容是不一樣的!我們再仔細觀察,發現,C語言的函數都打印了兩次,而系統調用接口只打印了一次。為什么呢??

這種現象就和fork函數以及我們下面要講的緩沖區有關了。

二、緩沖區

2.1、什么是緩沖區

緩沖區的本質就是一段內存空間。

我們知道,內存的速度比磁盤的速度快了幾個數量級。所以數據如果直接從內存寫到磁盤,那么訪問外設效率比較低,那就太消耗時間了。所以緩沖區的意義就是通過減少與外設的IO次數,來節省進程進行數據IO的時間。

所以C語言中就提供了緩沖區。而有了緩沖區的存在,可以提高整機效率,并提高用戶的響應速度。

2.2、刷新策略

~ 立即刷新。
~ 行刷新(行緩沖)。(常見的對顯示器進行數據刷新)以\n為標志
~ 滿刷新(全緩沖)。(常見的對磁盤文件寫入數據)

特殊情況:1、用戶強制刷新(fflush) ? ? ? ? ?2、進程退出

注:所有的設備,永遠都傾向于全緩沖,即緩沖區滿了才刷新,因為這樣只需要更少的IO操作,更少次的外設訪問,效率更高。

當然,我們要根據實際情況去改變刷新策略。如:顯示器是直接給用戶看的,一方面要照顧效率,一方面要照顧用戶體驗。所以顯示器一般使用行刷新。

2.3、緩沖區由誰提供

從上面的例子,我們發現直接往顯示器上打印的結果為4條,往文件打印的結果為7條,這跟緩沖區有關,同時這也說明了緩沖區一定不在Linux內核中,為什么?因為write是系統接口,如果在內核中,write也應該打印兩次。所以緩沖區是由C標準庫提供的。

我們之前所說的所有緩沖區都指的是用戶級語言層面提供的緩沖區。stdout,stdin,stderr對應的類型——FILE*,FILE是一個結構體,里面封裝了fd,同時還包括了一個緩沖區。

從源碼出發,我們可以來看一看FILE結構體:

2.4、重看問題

有了緩沖區的概念,我們就來解釋解釋問題引入中的現象。

首先,我們要先知道,代碼運行完了,并不代表數據已經刷新了。上面代碼中,使用C語言函數的操作在執行完了后,先將數據寫入了緩沖區中,并沒有直接向顯示器上打印。

第一次運行,沒有重定向操作,就是直接向顯示器打印,而顯示器的刷新策略是行刷新,且每個代碼后面都有\n,所以在調用fork之前,代碼不僅執行完了,而且數據都已經刷新了。所以fork對結果沒有影響。

第二次運行,我們有了重定向操作,于是函數就由向顯示器打印變成了向磁盤文件打印。所以刷新策略也由行刷新變成了滿刷新。那么\n就已經沒有意義了。所以代碼在運行到fork時,之前的代碼雖然已經運行完成了,但是數據還沒有刷新到文件中。數據還在當前進程對應的C標準庫中的緩沖區中,且該數據屬于父進程。

于是最后,我們fork創建了子進程。接著,父進程或子進程退出,這時數據會強制刷新出來。我們假設父進程先退出:父進程退出后,其數據強制刷新,而刷新的過程也是一種寫入,所以這時,為了父子進程的數據不會相互影響,就會發生寫時拷貝!這樣數據就會有兩份,于是父子進程各自退出時都會刷新各自的數據。(當然,如果子進程先退出也是同樣的)

所以,簡單總結來說:重定向導致刷新策略發生了改變(由行緩沖變成了全緩沖)。同時發生了寫時拷貝,父子進程各自刷新。

三、緩沖區的簡單實現

有了緩沖區的一些基本概念。我們可以自己實現一個簡單的帶有緩沖區的struct file。

主函數:

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;//當前緩沖區的結尾
};typedef struct MyFILE_ MyFILE;

?fopen函數的簡單實現

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函數的簡單實現

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函數簡單實現和fflush函數

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;}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/12044.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/12044.shtml
英文地址,請注明出處:http://en.pswp.cn/web/12044.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

將jar打包成exe可安裝程序,并在html頁面喚醒

一、exe4j將jar打包成exe 1.exe4j下載 下載地址&#xff1a;https://www.ej-technologies.com/download/exe4j/files 2.exe4j打包jar 2.1. welcome 可以選擇歷史配置&#xff0c;新增則直接下一步 2.2. project type選擇“jar in exe” mode 2.3. application info設置應用…

【接口測試_03課_-接口自動化思維梳理及Requests庫應用】

一、通過代碼&#xff0c;實現Jmeter 1、項目要放在虛擬環境里面&#xff0c;解釋器要使用虛擬環境的 上面是虛擬環境&#xff0c;下面是系統環境。2選一 venv目錄 查看當前虛擬環境已存在的依賴包 2、安裝Requests依賴包 1&#xff09;安裝命令 pip install requests 如果…

防火墻技術的演進,什么是下一代防火墻(NGFW)?

防火墻技術的演進 防火墻技術的演進經歷了不同階段&#xff0c;從包過濾防火墻到狀態檢測防火墻&#xff0c;再到集成多種安全功能的UTM&#xff08;統一威脅管理&#xff09;設備&#xff0c;最終發展到具備應用識別能力的NGFW&#xff08;下一代防火墻&#xff09;。 包過濾…

DTAS 尺寸公差分析及尺寸鏈計算-建模神器 — 用戶DIY裝配

工業互聯網&#xff08;工業4.0) 是未來智能制造的核心&#xff0c;工業軟件是智能制造的靈魂。 相關工業軟件及系統的自主研發是智能制造和質量升級轉型亟需解決的卡脖子環節&#xff0c;而公差分析軟件系統是前期質量研發精準設計、降本增效的關鍵。 數字化時代&#xff0…

知了匯智副總經理趙懋駿出席“走進阿里”CEO聯席會,共話AI大模型新趨勢

在智能科技日新月異的今天&#xff0c;匯智知了堂副總經理趙懋駿于3月28日受邀出席了在天府軟件園舉行的“走進阿里–2024年CEO聯席會”&#xff0c;會議聚焦阿里云AI技術的最新進展與行業應用&#xff0c;特別是“AI技術正在加速變革&#xff1a;大模型的歷史、現在與趨勢”&a…

手撕C語言題典——環形鏈表的約瑟夫問題

目錄 前言 一.故事背景 二.題目 ?編輯三.思路 1&#xff09;數組 ?編輯2&#xff09; 循環鏈表 四.代碼實現 搭配食用更佳哦~~ 數據結構之單單單——鏈表-CSDN博客 數據結構之單鏈表的基本操作-CSDN博客 前面學了單鏈表的相關知識&#xff0c;我們來嘗試做一下關于…

centos 把nginx更新到最新版本

yum install epel-release # 添加 EPEL 軟件倉庫&#xff0c;這是 Nginx 官方軟件倉庫的依賴項 yum install yum-utils # yum-utils 包含了 yum-config-manager 工具&#xff0c;它可以讓您輕松地啟用、禁用或配置 yum 軟件倉庫 vi /etc/yum.repos.d/nginx.repo # 增加以下內容…

灌區信息化管理平臺系統包含哪些內容?(全面介紹)

政策背景 2022年12月29日&#xff0c;水利部啟動48處大中型灌區開展數字孿生灌區先行先試建設。 2023年2月24日&#xff0c;《2023年農村水利水電工作要點》:2023年農村水利水電工作的總體思路包括:緊盯保障國家糧食安全&#xff0c;加快推進大中型灌區現代化改造&#xff0c;…

Linux repo包安裝Nginx

Linux repo包安裝Nginx 1. 將nginx.repo 文件拷貝到 /etc/yum.repos.d 目錄2.找到原來的NGINX配置文件打包備份3.執行Nginx安裝命令4. 重啟 nginx -s reload5. 查看Nginx版本 1. 將nginx.repo 文件拷貝到 /etc/yum.repos.d 目錄 cp nginx.repo /etc/yum.repos.d2.找到原來的…

jQuery 入門:輕松創建與插入節點

在Web開發中&#xff0c;動態地創建和管理DOM&#xff08;文檔對象模型&#xff09;節點是一項基本且強大的技能。jQuery&#xff0c;作為JavaScript的一個流行庫&#xff0c;以其簡潔的API簡化了這一過程。本文將通過一個簡單的示例&#xff0c;介紹如何使用jQuery來創建新的D…

【力扣一輪】鏈表-刪除鏈表指定值的元素

刪除鏈表指定元素 力扣鏈接 代碼隨想錄題解 分為兩個版本&#xff0c;一個是帶有虛擬頭節點&#xff0c;一個是不帶。 無論是帶有還是不帶有&#xff0c;我都遇到了這幾個問題&#xff1a; ①while循環時的判斷&#xff0c;首先要判斷當前節點是否為空&#xff0c;接著才能…

bmi088-linux驅動(I2C)

電氣特性&#xff1a; 在正常工作時&#xff0c;gyro 工作電流為5mA&#xff0c;acc 工作電流為150uA。 SPI 時鐘和數據電平范圍 0 -3.6 結構框圖如下&#xff1a; 硬件連接圖如下&#xff1a; note&#xff1a; 1. 通過PS引腳選擇通訊協議&#xff0c;上拉引腳則選擇的是I2C…

系統定期執行命令的方法

系統定期執行命令的方法 一、進入超級用戶下 執行命令&#xff1a;sudo su 二、添加要執行的命令 例子&#xff1a;每天0點執行一次myapp.sh命令 先后輸入&#xff1a;crontab -e、 1、 回車 設置每天0點執行一次myapp.sh操作&#xff0c;需要寫絕對路徑 含義&#xff1…

離線修復.dll,Microsoft Visual C++

在安裝mysql時遇到下面的問題&#xff0c;如果是有網絡的情況下微軟管網下載安裝就行了&#xff0c;用的服務器不允許連接互聯網。 后面經過尋找&#xff0c;找到了一個修復工具&#xff0c;可一次修復所有的問題&#xff0c;特別好用分享給寶子們。 下載鏈接&#xff1a;http…

樹莓派 4B putty遠程連接登錄顯示拒絕訪問,密碼修改

putty顯示拒絕訪問 可能是樹莓派的ip沒有找到正確的 在下載系統鏡像的時候&#xff0c;會提示設置wifi 這里設置的WiFi和密碼需記住&#xff0c;主機名也需記住 可以在手機打開熱點&#xff08;將熱點的賬號和密碼改為跟你設置的wifi一樣的&#xff09; 可以在手機后臺查看…

頁面埋點H5 大數據uniapp 按需要更改代碼就行

邏輯思路 跳轉頁面前&#xff0c;記錄當前頁面的信息停留的時長以及各種信息&#xff0c;然后等走的時候再將記錄的信息發送出去 1.記錄當前頁面信息的函數 // 埋點通用接口 // triggerType: 必傳 類型 entryStr(進入) || leaveStr(離開) || String:自定義事件描述 // pageU…

微信小程序支付教程

微信小程序支付教程 Person&#xff1a; 微信小程序支付有幾種版本&#xff0c;分別是什么&#xff0c;寫一個詳細教程介紹下 ChatGPT&#xff1a; 微信小程序支付主要有兩種版本&#xff0c;分別為&#xff1a;JSSDK版本&#xff08;v1.0&#xff09;和WeixinJSBridge版本&…

超寬輸送帶耐熱性能怎么樣

超寬輸送帶耐熱性能解析 隨著工業領域的不斷發展和技術革新&#xff0c;超寬輸送帶的應用越來越廣泛。這種輸送帶在冶金、建筑、化工等多個行業中發揮著至關重要的作用&#xff0c;特別是在高溫環境下&#xff0c;其耐熱性能更是備受關注。那么&#xff0c;超寬輸送帶的耐熱性…

解釋下泛型擦除

在Java中&#xff0c;泛型擦除&#xff08;Type Erasure&#xff09;是Java泛型實現的一個重要概念。由于Java的泛型是在編譯時實現的&#xff08;稱為編譯時類型檢查&#xff09;&#xff0c;而在運行時&#xff0c;Java虛擬機&#xff08;JVM&#xff09;并不支持泛型&#x…

HDFS小文件優化方法

1、HDFS小文件弊端 HDFS上每個文件都要在namenode上建立一個索引&#xff0c;這個索引的大小約為150byte&#xff0c;這樣當小文件比較多的時 候 &#xff0c;就會產生很多的索引文件&#xff0c;一方面會大量占用namenode的內存空間 &#xff0c;另一方面就是索引文件過大是的…