Linux系統:虛擬文件系統與文件緩沖區(語言級內核級)

本節重點

  • 初步理解一切皆文件
  • 理解文件緩沖區的分類
  • 用戶級文件緩沖區與內核級文件緩沖區
  • 用戶級文件緩沖區的刷新機制
  • 兩級緩沖區的分層協作

一、虛擬文件系統

1.1 理解“一切皆文件”

我們都知道操作系統訪問不同的外部設備(顯示器、磁盤、鍵盤、鼠標、網卡)時都會通過相應的驅動程序,由于各種外設之間的差異在驅動程序中對每個外設的輸入輸出(如獲取設備狀態、屬性)的相關方法的實現都不盡相同:

?我們說操作系統是對軟硬件資源進行管理的軟件,在內核中要對硬件資源進行管理首先需要讓操作系統看到硬件資源,也就是將硬件資源“先描述再組織”:

在操作系統內核中通過類似struct device的結構體來對每種外設進行描述,再通過鏈表的方式將硬件資源管理起來,此時這個數據結構就表示操作系統啟動時默認看到的和打開的外設資源:

當用戶運行自己的代碼與數據時,操作系統就會在內核空間創建進程PCB,其中PCB中的struct files struct指針指向的文件描述符表則記錄了該進程打開的文件的數量。而我們知道文件描述符表本質上是元素為struct file的一維數組,struct file中則詳細記錄了被打開文件的文件緩沖區和元數據,關鍵的是其中還記錄了指向文件操作的各種方法的指針(函數指針),這樣對文件的操作會通過函數指針跳轉到不同的對應外設的驅動層。

這樣即使外設之間存在差異,驅動程序的設計大相徑庭用戶訪問涉及到不同類型外設的文件時也能獲得相似的方法,以為在內核通過函數指針已經幫用戶完成了差異化的方法調用。

二、文件緩沖區

2.1 什么是緩沖區

緩沖區是內存空間的一部分,用來暫時存儲輸入或者輸出的數據內容,這部分預留的空間就叫做緩沖區。緩沖區根據其對接的是輸入設備還是輸出設備分為輸入緩沖區與輸出緩沖區。

2.2 為什么引入緩沖區?

關鍵1:語言級文件操作都會調用系統調用

在介紹操作系統時我們了解到:操作系統為了不直接暴露內核,為上層用戶提供了各類系統調用。在語言層面對文件操作的各類函數接口底層都封裝了系統調用。

例如,以C語言為例fopen,fread,fwrite底層都分別封裝了open,read,write系統調用。

所以本質上我們使用各類編程語言進行文件操作(如I/O操作)都會調用系統調用。

關鍵2:系統調用是有代價的?

在之后的學習中我們會了解到,當程序執行系統調用時,CPU會從用戶態切換到內核態這個過程涉及到保護用戶程序的寄存器狀態,切換頁表,加載內核代碼段等操作。當系統調用完成時,CPU會從內核態返回到用戶態,此時CPU需要恢復用戶程序的寄存器狀態,整個操作會涉及到數百到數千個CPU周期。

關鍵3:緩沖區的引入可以減少系統調用次數

以向文件中寫入數據為例,當我們引入緩沖區的概念后,對文件的輸入操作意味著我們可以逐漸將數據塊輸入到緩沖區中,然后通過適當的緩沖機制調用系統調用將數據塊整體寫入到文件中,大大減少了系統調用的次數,大大提高了輸入效率。

2.3?緩沖區的分類

2.3.1 用戶級(C語言為例)

C標準庫中的I/O函數(printf、fwrite、fgets)均圍繞流的概念設計。每個流(stdout、stderr、stdin、用戶自定義的文件流)都由一個FILE結構體來表示,該結構體包含一個緩沖區以及緩沖策略(行緩沖、全緩沖、無緩沖)。

在C標準庫中對結構體FILE的描述如下:

//FILE本質上是定義的一個宏在/usr/include/stdio.h中typedef struct _IO_FILE FILE;
//在/usr/include/libio.h
struct _IO_FILE 
{
int _flags;                /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags//緩沖區相關
/* The following pointers correspond to the C++ streambuf protocol. */
/* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
char* _IO_read_ptr;       /* Current read pointer */ 
char* _IO_read_end;       /* End of get area. */ 
char* _IO_read_base;      /* Start of putback+get area. */  
char* _IO_write_base;     /* Start of put area. */   
char* _IO_write_ptr;      /* Current put pointer. */  
char* _IO_write_end;      /* End of put area. */  
char* _IO_buf_base;       /* Start of reserve area. */ 
char* _IO_buf_end;        /* End of reserve area. *//* The following fields are used to support backing up and undo. */char *_IO_save_base;    /* Pointer to start of non-current get area. */char *_IO_backup_base;  /* Pointer to first valid character of backup area */char *_IO_save_end;     /* Pointer to end of non-current get area. */struct _IO_marker *_markers;struct _IO_FILE *_chain;int _fileno;            //封裝的?件描述符#if 0
int _blksize;
#else
int _flags2;
#endif
_IO_off_t _old_offset;  /* This used to be _offset but it's too small.  */
#define __HAVE_COLUMN   /* temporary */
/* 1+column number of pbase(); 0 is unknown. */
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];
/*  char* _save_gptr;  char* _save_egptr; */
_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};
?緩沖機制

在C標準庫(stdio.h)總共定義了三個緩沖機制,每個流(FILE結構體)在其生命周期中通常只配置一個緩沖機制。以下是對三個緩沖機制的介紹:

注意事項:

除了以上默認的刷新方式下列特殊清空也會引發緩沖區的刷新:

  • 緩沖區被寫滿
  • 顯式刷新(如調用flush)

當緩沖區為行緩沖但是始終沒有遇到換行符(\n)時,當緩沖區滿時會自動提交。?

當涉及磁盤文件操作時默認為全緩沖,當所操作的流涉及一個終端(顯示器)時默認為行緩沖,stderr默認不帶緩沖區即無緩沖。

這里舉一個代碼示例:

//code.c
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{const  char* s1="hello printf\n";const  char* s2="hello fwrite\n";printf("%s",s1);fwrite(s2,1,strlen(s2),stdout);fork();return 0;
}

運行結果:

?首先printf與fwrite將字符串寫入stdout對應的緩沖區中,當涉及到對終端(顯示器)的操作時為行緩沖,所以字符串會依次刷新提交。

此時我們執行以下指令:將程序重定向到一個文本文件(text.txt)中

./code 1> text.txt

?運行結果:

?此時我們發現同一份代碼數據被打印了兩次,原因是當我們進行重定向操作后就成為了用戶對磁盤文件(text.txt)的文件操作,默認緩沖機制變成了全緩沖

當我們創建子進程之前,父進程的兩個數據(hello printf / hello fwrite)還在緩沖區中并沒有被刷新提交,而我們知道子進程是父進程的副本,當創建子進程時緩沖區中的數據也一并拷貝給了子進程,當程序結束后會自動刷新text.txt文件流的緩沖區,導致數據被打印了兩次。

2.3.2 內核級

在Linux系統中,內核級緩沖區是用于在內核空間和用戶空間之間傳遞數據的關鍵機制。它通常用于提高I/O操作的效率,減少系統調用的次數,并優化數據的傳輸。

內核級緩沖區的類型:

1> 頁緩存

用于緩存文件數據,減少磁盤I/O操作。當文件被讀取時,數據會被緩存在頁緩存中,后續的讀取操作可以直接從緩存中獲取數據,而不需要再次訪問磁盤。

2> 塊設備緩沖區

用于緩存塊設備的數據,如硬盤的塊數據。它與頁緩存類似,但更專注于塊設備的I/O操作。

3> 套接字緩沖區

用于網絡通信,管理網絡數據包的傳輸。每個網絡數據包都會被封裝在sk_buff結構中,以便在內核中進行處理。

與用戶級緩沖區類似,內核級緩沖區也有刷新機制但是在實現方面會復雜很多。以為在內核層面操作系統要考慮的因素會更多,比如刷新操作可能涉及大量的內存操作,不當的刷新策略可能導致系統資源耗盡或內存泄漏,還有在多核或多線程環境下,內核級緩沖區的刷新機制需要處理并發訪問問題。這通常需要引入復雜的同步機制,如自旋鎖或讀寫鎖,以確保數據的一致性和完整性等等

?以下是內核級緩沖區的刷新機制,可以來了解一下:

  • 定期刷新:內核會定期將緩沖區中的數據寫入存儲設備。這種刷新通常由內核的守護進程負責,確保數據在一定時間間隔內被寫入磁盤。
  • 顯式刷新:應用程序可以通過系統調用(如?fsync?或?fdatasync)顯式請求將緩沖區中的數據刷新到存儲設備。
  • 緩沖區滿時刷新:當內核緩沖區達到一定容量時,內核會自動將數據刷新到存儲設備。
  • 文件關閉時刷新:當應用程序關閉文件時,內核會自動將與該文件相關的緩沖區數據刷新到存儲設備。
  • 內存壓力:當系統內存不足時,內核可能會主動刷新緩沖區以釋放內存。這種機制確保系統在高內存壓力下仍能正常運行。?

2.3 兩級緩沖區的聯系

關鍵詞:分層協作

當應戶程序通過用戶級緩沖區寫入數據時,數據首先存儲在用戶空間的緩沖區中。當緩沖區滿或顯式調用刷新函數時,數據會被復制到內核級緩沖區。內核級緩沖區進一步管理數據的物理寫入操作,確保數據最終被寫入磁盤或發送到網絡設備。

我們可以通過下圖來理解:

這種分層緩沖機制減少了頻繁的系統調用,提高了數據處理的效率。同時,內核級緩沖區還可以利用更高級的優化技術,如延遲寫入和批量處理,進一步提升系統性能。

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

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

相關文章

在c++中老是碰到string,這是什么意思?

定義一個string類型變量的引用&#xff0c;相當于給現有變量起個別名&#xff0c;與指針還是不一樣的。比如string a;string& ba;這兩句&#xff0c;b與a實際上是一回事&#xff0c;表示的是同一塊內存。 std是系統的一個命名空間(有關命名空間可以參閱namespace_百度百科)…

Day21 奇異值分解(SVD)全面解析

一、奇異值分解概述 奇異值分解是線性代數中一個重要的矩陣分解方法&#xff0c;對于任何矩陣&#xff0c;無論是結構化數據轉化成的“樣本 * 特征”矩陣&#xff0c;還是天然以矩陣形式存在的圖像數據&#xff0c;都能進行等價的奇異值分解&#xff08;SVD&#xff09;。 二…

akshare爬蟲限制,pywencai頻繁升級個人做量化,穩定數據源和券商的選擇

做量化&#xff0c;數據和交易接口是策略和自動化交易的基石&#xff0c;而穩定的數據和快人一步的交易接口是個人做量化的催化劑。 之前寫過一篇文章&#xff1a;個人做量化常用的數據&#xff0c;多以爬蟲為主&#xff0c;最近akshare爬蟲限制&#xff0c;pywencai頻繁升級。…

數字簽名與證書

1. 數字簽名與證書 摘要算法用來實現完整性&#xff0c;能夠為數據生成獨一無二的“指紋”&#xff0c;常用的算法是 SHA-2&#xff1b;數字簽名是私鑰對摘要的加密&#xff0c;可以由公鑰解密后驗證&#xff0c;實現身份認證和不可否認&#xff1b;公鑰的分發需要使用數字證書…

Ubuntu22.04安裝顯卡驅動/卸載顯卡驅動

報錯 今日輸入nvidia-smi報錯,在安裝了535和550,包括560都沒辦法解決,但是又怕亂搞導致環境損壞,打算把顯卡卸載然后重新安裝系統默認推薦版本的顯卡驅動 qinqin:~$ nvidia-smi Failed to initialize NVML: Driver/library version mismatch NVML library version: 560.35卸載…

Web 架構之負載均衡全解析

文章目錄 一、引言二、思維導圖三、負載均衡的定義與作用定義作用1. 提高可用性2. 增強性能3. 實現擴展性 四、負載均衡類型硬件負載均衡代表設備優缺點 軟件負載均衡應用層負載均衡代表軟件優缺點 網絡層負載均衡代表軟件優缺點 五、負載均衡算法輪詢算法&#xff08;Round Ro…

linux下的Redis的編譯安裝與配置

配合做開發經常會用到redis&#xff0c;整理下編譯安裝配置過程&#xff0c;僅供參考&#xff01; --------------------------------------Redis的安裝與配置-------------------------------------- 下載 wget https://download.redis.io/releases/redis-6.2.6.tar.gz tar…

A2A大模型協議及Java示例

A2A大模型協議概述 1. 協議作用 A2A協議旨在解決以下問題&#xff1a; 數據交換&#xff1a;不同應用程序之間的數據格式可能不一致&#xff0c;A2A協議通過定義統一的接口和數據格式解決這一問題。模型調用&#xff1a;提供標準化的接口&#xff0c;使得外部應用可以輕松調…

關鍵點檢測--使用YOLOv8對Leeds Sports Pose(LSP)關鍵點檢測

目錄 1. Leeds Sports Pose數據集下載2. 數據集處理2.1 獲取標簽2.2 將圖像文件和標簽文件處理成YOLO能使用的格式 3. 用YOLOv8進行訓練3.1 訓練3.2 預測 1. Leeds Sports Pose數據集下載 從kaggle官網下載這個數據集&#xff0c;地址為link&#xff0c;下載好的數據集文件如下…

20250508在WIN10下使用移遠的4G模塊EC200A-CN直接上網

1、在WIN10/11下安裝驅動程序&#xff1a;Quectel_Windows_USB_DriverA_Customer_V1.1.13.zip 2、使用移遠的專用串口工具&#xff1a;QCOM_V1.8.2.7z QCOM_V1.8.2_win64.exe 3、配置串口UART42/COM42【移遠會自動生成連續三個串口&#xff0c;最小的那一個】 AT命令&#xf…

第J7周:ResNeXt解析

&#x1f368; 本文為&#x1f517;365天深度學習訓練營 中的學習記錄博客&#x1f356; 原作者&#xff1a;K同學啊 目標 具體實現 &#xff08;一&#xff09;環境 語言環境&#xff1a;Python 3.10 編 譯 器: PyCharm 框 架: Tensorflow &#xff08;二&#xff09;具體…

C++之類和對象:初始化列表,static成員,友元,const成員 ……

目錄 const成員函數&#xff1a; 前置和后置重載&#xff1a; 取地址及const取地址操作符重載&#xff1a; 初始化列表&#xff1a; explicit關鍵字&#xff1a; static成員&#xff1a; 友元&#xff1a; 友元函數&#xff1a; 友元類&#xff1a; 內部類&#xff1a…

uni-app 中的條件編譯與跨端兼容

uni-app 為了實現一套代碼編譯到多個平臺&#xff08;包括小程序&#xff0c;App&#xff0c;H5 等&#xff09;&#xff0c;引入了條件編譯機制。 通過條件編譯&#xff0c;我們可以針對不同的平臺編寫特定的代碼&#xff0c;從而實現跨端兼容。 一、條件編譯的作用 平臺差異…

Linux平臺下SSH 協議克隆Github遠程倉庫并配置密鑰

目錄 注意&#xff1a;先提前配置好SSH密鑰&#xff0c;然后再git clone 1. 檢查現有 SSH 密鑰 2. 生成新的 SSH 密鑰 3. 將 SSH 密鑰添加到 ssh-agent 4. 將公鑰添加到 GitHub 5. 測試 SSH 連接 6. 配置 Git 使用 SSH 注意&#xff1a;先提前配置好SSH密鑰&#xff0c;然…

[C++] 大數減/除法

目錄 高精度博客 - 前兩講高精度減法高精度除法高精度系列函數完整版 高精度博客 - 前兩講 講次名稱鏈接高精加法[C] 高精度加法(作用 模板 例題)高精乘法[C] 高精度乘法 高精度減法 void subBIG(int x[], int y[], int z[]){z[0] max(x[0], y[0]);for(int i 1; i < …

視頻添加字幕腳本分享

腳本簡介 這是一個給視頻添加字幕的腳本&#xff0c;可以方便的在指定的位置給視頻添加不同大小、字體、顏色的文本字幕&#xff0c;添加方式可以直接修改腳本中的文本信息&#xff0c;或者可以提前編輯好.srt字幕文件。腳本執行環境&#xff1a;windowsmingwffmpeg。本方法僅…

ubuntu nobel + qt5.15.2 設置qss語法識別正確

問題展示 解決步驟 首選項里面的高亮怎么編輯選擇都沒用。如果已經有generic-highlighter和css.xml&#xff0c;直接修改css.xml文件最直接&#xff01; 在generic-highlighter目錄下找到css.xml文件&#xff0c;位置是&#xff1a;/opt/Qt/Tools/QtCreator/share/qtcreator/…

洛谷P7528 [USACO21OPEN] Portals G

P7528 [USACO21OPEN] Portals G luogu題目傳送門 題目描述 Bessie 位于一個由 N N N 個編號為 1 … N 1\dots N 1…N 的結點以及 2 N 2N 2N 個編號為 1 ? 2 N 1\cdots 2N 1?2N 的傳送門所組成的網絡中。每個傳送門連接兩個不同的結點 u u u 和 v v v&#xff08; u …

C++STL——priority_queue

優先隊列 前言優先隊列仿函數頭文件 前言 本篇主要講解優先隊列及其底層實現。 優先隊列 優先隊列的本質就是個堆&#xff0c;其與queue一樣&#xff0c;都是容器適配器&#xff0c;不過優先隊列是默認為vector實現的。priority_queue的接口優先隊列默認為大根堆。 仿函數 …

助力你的Neovim!輕松管理開發工具的魔法包管理器來了!

在現代編程環境中&#xff0c;Neovim 已經成為許多開發者的編輯器選擇。而針對 Neovim 的各種插件與功能擴展&#xff0c;則是提升開發體驗的重要手段。今天我們要介紹的就是一個強大而便捷的開源項目——mason.nvim&#xff0c;一個旨在簡化和優化 Neovim 使用體驗的便攜式包管…