Linux:(五種IO模型)

目錄

一、對IO的重新認識

二、IO的五種模型

1.阻塞IO

2.非阻塞IO

3.信號驅動IO

4.IO多路轉接

5.異步IO

6.一些概念的解釋

三、非阻塞IO的代碼實現

1.fcntl

2.實現主程序


一、對IO的重新認識

如果有人問你IO是什么,你該怎么回答呢?

你可能會說,IO不就是input和output表示輸入和輸出,輸入表示把數據從硬盤等外設拷貝到內存,而輸出表示把數據從內存拷貝到其他外設。

雖然這樣說沒什么大問題,但還不夠深刻。

我們不妨設想下面的現象,有一個進程,調用read/recv這樣的系統調用讀取數據。如果此時讀取條件不滿足,那就沒有數據可供進程讀取,進程只就會一直等待數據準備好。

IO除了拷貝數據需要消耗時間,還包含這個等待的過程所以我們使用的系統調用除了拷貝代碼,也包含了等的這部分代碼。

也就是說,IO=等+數據拷貝

那什么是高效IO呢?

我們知道,IO過程我們在意的是拷貝,而不是等待。而拷貝需要的時間是由電路還有系統實現等保證的。隨著科技的發展,拷貝本身花費的時間已經基本沒有提升空間了,所以拷貝本身的效率已經很難再有提升了。那么等待時間的長度就決定了IO的效率。

換句話說,單位時間內,等待的比重越低,IO效率越高。

二、IO的五種模型

1.阻塞IO

在內核將數據準備好之前,系統調用會一直等待。我們之前寫代碼使用的IO接口讀取文件描述符,默認都使用阻塞IO方式。

下圖就是阻塞IO的示意圖,進程調用recvfrom這樣的IO接口從內核中讀取數據。如果數據沒有準備好,進程就會阻塞在調用處等待,數據準備好后,才會將內核中的數據拷貝到用戶緩沖區,并給出返回值。

阻塞IO是最常見的IO模型,也最簡單,我們之前寫的所有代碼,IO都是阻塞式的。

2.非阻塞IO

如果內核還未將數據準備好,系統調用仍然會直接返回,并且返回EAGAN或者EWOULDBLOCK錯誤碼。

如圖所示,進程調用recvfrom從內核緩沖區中讀取數據。如果數據沒有準備好,就會給進程返回一個EWOULDBLOCK錯誤碼,告訴進程數據還沒準備好,進程就會接著去干自己的事情。

過了一段時間,進程還會調用recvfrom讀取數據,不斷反復,直到數據準備好。接著系統調用完成拷貝并返回成功的返回值。

非阻塞IO需要程序員設計循環代碼,反復嘗試讀寫文件描述符,這個過程稱為輪詢。但輪詢對CPU有一定的性能浪費,只有特定場景下才使用。

3.信號驅動IO

信號驅動IO會在內核將數據準備好的時候,發送SIGIO信號通知進程進行IO操作。

如圖所示,信號驅動IO模型,該模式使用信號處理函數執行IO。

首先使用signal注冊信號處理函數為包含IO系統調用的函數。所以只要進程收到信號,就可以在處理函數中調用recvfrom拷貝已經準備好的數據。

也就是說,只要數據準備完成了,進程就會收到信號,進程直接來拷貝就可以了。其余時間進程還可以繼續執行自己的代碼。

但是我們之前也說過,如果我們給一個進程同時發很多信號,只有兩個能被最終遞達。而這里的信號丟失就相當于讀取次數減少,就相當于數據丟失。所以,這種很少有符合這種模式的IO狀態。

4.IO多路轉接

IO多路轉接可以理解為多個阻塞IO同時進行,并不斷遍歷檢測哪個IO的文件描述符準備好了,準備好了就會執行拷貝。

如圖所示為IO多路轉接模式,它將IO的等待和拷貝分開了。

進程調用select系統調用等待內核中的數據就緒,就緒以后會通知進程調用recvfrom來將數據拷貝到用戶緩沖區中。

由于多路轉接可以同時等待多個文件描述符。所以,當一個或者多個文件的緩沖區中數據就緒時,都會通知上層用戶讀取。而且每個拷貝過程也是并行的,還是免不了等,但是等的比重降低了很多,從而提高了IO的效率。

多路轉接既是效率最高的IO模式,也是我們以后講解的重點。

5.異步IO

當一個異步IO調用發出后,調用者不會立刻得到結果,而是在調用發出后,被調用者通過狀態、信號等來通知調用者,或通過回調函數處理這個調用。

下圖表示異步IO,進程調用aio_read,將等待數據就緒和將數據拷貝到用戶緩沖區兩個步驟的工作全部交給操作系統來完成。當操作系統完成兩個步驟以后,直接通知上層用戶去用戶緩沖區中讀取數據即可。

也就是,進程不需要再考慮數據的IO,而是將其全權交給操作系統完成。

6.一些概念的解釋

什么是同步IO和異步IO?

同步和異步的區別在于消息通信的機制。

所謂同步,就是在發出一個調用時,在沒有得到結果之前,該調用就不返回,但是一旦調用返回,就得到返回值了。

換句話說就是,調用者在主動等待這個調用的結果。

而異步則是調用開始執行后直接返回,調用者不會立刻得到結果,而是在調用返回后,被調用者通過狀態、信號等通知調用者或通過回調函數處理。

話句話說,就是把事情交給了其他應用去做,自己只根據通信數據接收處理結果。

線程同步和同步IO有什么關系?

我們在講解Linux線程時也提到了同步。

線程同步表示多個線程同時對臨界資源進行操作時,系統為了保證沒有線程處于饑餓狀態,會以一定的順序安排各個線程的執行順序。

而同步IO表示處理數據的進程本身是否全權參與IO過程。

也就是,同步IO和線程同步之間,除了都有同步這個詞之外沒有任何關系。

三、非阻塞IO的代碼實現

1.fcntl

int fcntl(int fd, int cmd, ... /* arg */ );
  • 頭文件unistd.h、fcntl.h

  • 功能:修改文件描述符的屬性或對其進行其他操作。

  • 參數:int fd需要操作的文件描述符。int cmd表示對描述符的操作。...表示可變參數列表,傳入的cmd不同,參數也不同

  • 返回值:成功返回非-1的值,失敗返回-1。

fcntl函數有5種功能:

  • 復制一個現有的描述符(cmd=F_DUPFD).

  • 獲得/設置文件描述符標記(cmd=F_GETFD或F_SETFD).

  • 獲得/設置文件狀態標記(cmd=F_GETFL或F_SETFL).

  • 獲得/設置異步I/O所有權(cmd=F_GETOWN或F_SETOWN).

  • 獲得/設置記錄鎖(cmd=F_GETLK,F_SETLK或F_SETLKW).

我們只使用第三個功能,即獲取/設置文件狀態標記,可將一個文件描述符設置為非阻塞。我們寫一個SetNonBlock函數支持該功能。

//將文件描述符設為非阻塞
void SetNonBlock(int fd)
{int fl = fcntl(fd, F_GETFL);//獲取文件描述符的標志,該標志是一個位圖結構if(fl < 0)//獲取失敗{std::cerr << "fctnl:" << strerror(errno) << std::endl;//打印錯誤碼}else{fcntl(fd, F_SETFL, fl | O_NONBLOCK);//將該文件描述符設為非阻塞}
}

2.實現主程序

由于我們從標準輸入流(文件描述符為0)中讀取數據,所以只要我們敲擊鍵盤輸入文字,就相當于向標準輸入流中寫入數據。

main.cc

#include"util.hpp"
#include<iostream>int main()
{SetNonBlock(0);//設置文件描述符為非阻塞while(1){char buffer[1024];ssize_t n = read(0, buffer, sizeof(buffer)-1);//讀取數據if(n > 0)//讀到了數據{buffer[n] = '\0';std::cout << buffer << std::endl;}else if(n == 0)//讀到了結尾{std::cout << "read end" << std::endl;break;}else//n等于-1有兩種情況,一種是讀取出錯,另一種是數據還沒準備好,read只能按-1返回{if (errno == EAGAIN)//錯誤碼為EAGAIN表示數據還沒有準備好{//std::cout << "我沒錯, 只是沒有數據" << std::endl;print_work();//程序繼續執行自己的事}else if (errno == EINTR)//錯誤碼為EINTR表示讀取時進程收到了信號,需要進行處理,讀取就被暫時打斷了。{continue;//繼續循環}else//這次就是出錯了,打印錯誤碼就可以了{std::cout << " errno: " << strerror(errno) << std::endl;break;}}sleep(1);}return 0;
}

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

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

相關文章

將電腦控制手機編寫為MCP server

文章目錄 電腦控制手機后,截屏代碼復習MCP server構建修改MCP的config文件測試效果困惑電腦控制手機后,截屏代碼復習 def capture_window(hwnd: int, filename: str = None) -> dict:""&

[ctfshow web入門] web6

前置知識 入口點(目錄)爆破 還記得之前說過網站的入口的嗎&#xff0c;我們輸入url/xxx&#xff0c;其中如果url/xxx存在&#xff0c;那么訪問成功&#xff0c;證明存在這樣一個入口點&#xff1b;如果訪問失敗則證明不存在此入口點。所以我們可以通過遍歷url/xxx&#xff0c;…

【計算機網絡】Linux配置SNAT策略

什么是NAT&#xff1f; NAT 全稱是 Network Address Translation&#xff08;網絡地址轉換&#xff09;&#xff0c;是一個用來在多個設備共享一個公網 IP上網的技術。 NAT 的核心作用&#xff1a;將一個網絡中的私有 IP 地址&#xff0c;轉換為公網 IP 地址&#xff0c;從而…

Mathematics | Branch

注&#xff1a;本文為“遇見數學”翻譯的 “數學分支概覽” 兩篇文章合輯。 數學世界的版圖&#xff1a;主要分支概覽&#xff08;上&#xff09; 原創 遇見數學 2025 年 04 月 03 日 12:02 河南 數學的分支&#xff08;Areas of Mathematics&#xff09; 在文藝復興之前&am…

Ubuntu(CentOS、Rockylinux等)快速進入深度學習pytorch環境

這里寫自定義目錄標題 安裝進入系統&#xff08;如Ubuntu22.04&#xff09;安裝anacondapip、conda換源pip換源conda換源 安裝nvidia安裝pytorch環境針對于wsl的優化 安裝進入系統&#xff08;如Ubuntu22.04&#xff09; docker 、 wsl 、 雙系統 、服務器系統 推薦 Ubuntu 20…

什么是混雜模式?為什么 macvlan 依賴它

在 macvlan 場景中&#xff0c;物理網絡是否支持混雜模式&#xff08;Promiscuous Mode&#xff09; 直接影響 macvlan 虛擬接口的通信能力。以下是詳細解釋和操作指南&#xff1a; 一、什么是混雜模式&#xff1f;為什么 macvlan 依賴它&#xff1f; 混雜模式的定義 當物理網絡…

物理數據流圖

物理數據流圖&#xff08;Physical Data Flow Diagram, PDFD&#xff09;詳解 物理數據流圖是結構化系統分析中的一種建模工具&#xff0c;用于描述系統在物理環境下的具體實現方式&#xff0c;包括硬件、軟件、人工操作和物理文件等實際組成部分。它與**邏輯數據流圖&#xf…

Linux開發工具——vim

&#x1f4dd;前言&#xff1a; 上篇文章我們講了Linux開發工具——apt&#xff0c;這篇文章我們來講講Linux開發工具——vim &#x1f3ac;個人簡介&#xff1a;努力學習ing &#x1f4cb;個人專欄&#xff1a;Linux &#x1f380;CSDN主頁 愚潤求學 &#x1f304;其他專欄&a…

在 Langflow 中構建靈活的自定義組件:從基礎到高級實踐

本文深入探討了如何在 Langflow 平臺中創建功能豐富的自定義組件。通過詳細的目錄結構解析、分步實現指南和多個實戰案例&#xff0c;幫助開發者掌握利用 Python 生態擴展低代碼平臺的方法&#xff0c;打造高效的數據處理流程。 理解組件架構設計 自定義組件是在 Langflow 中創…

stm32+LTR-390UV使用教程含源碼

stm32LTR-390UV使用教程含源碼 &#xff08;csdn首發源碼&#xff09;&#xff0c;本人大四學生&#xff0c;考研已上岸&#xff0c;畢設做的全向輪小車&#xff0c;這個是環境檢測部分LTR-390UV使用教程 文章目錄 目錄 文章目錄 前言 一、硬件準備與連接 二、數據手冊 1.…

【嵌入式系統設計師】知識點:第2章 嵌入式系統硬件基礎知識

提示:“軟考通關秘籍” 專欄圍繞軟考展開,全面涵蓋了如嵌入式系統設計師、數據庫系統工程師、信息系統管理工程師等多個軟考方向的知識點。從計算機體系結構、存儲系統等基礎知識,到程序語言概述、算法、數據庫技術(包括關系數據庫、非關系型數據庫、SQL 語言、數據倉庫等)…

Java 項目灰度發布的詳細實現與實踐

前言 灰度發布是一種通過逐步將新功能或更新推向一部分用戶來降低上線風險的技術。本文將詳細介紹如何在 Java 項目中實現灰度發布&#xff0c;并提供相關的配置參數、代碼示例以及 uml 圖&#xff0c;幫助您更好地理解和應用這一技術。 一、灰度發布的核心思想 灰度發布的核…

使用 Swift 實現 LRU 緩存淘汰策略

&#x1f4cc; 實現思路 一、核心目標 我們要實現一個緩存類&#xff1a; 支持通過 get(key) 獲取緩存的值&#xff1b;支持通過 put(key, value) 寫入緩存&#xff1b;緩存容量有限&#xff0c;當超過容量時要淘汰最久未使用的元素。 二、為什么用「哈希表 雙向鏈表」 功…

C#中為自定義控件設置工具箱圖標

在C#中為自定義控件設置工具箱圖標&#xff0c;可通過以下步驟實現&#xff1a; ### 步驟說明&#xff1a; 1. **準備圖標文件** - 創建或選擇一個16x16像素的位圖&#xff08;.bmp&#xff09;文件&#xff0c;建議使用透明背景以確保清晰顯示。 2. **添加位圖到項目** -…

Linux數據庫:【數據庫基礎】【庫的操作】【表的操作】

目錄 一.數據庫基礎 1.1什么是數據庫 1.2基本使用 1.2.1連接服務器 1.2.2服務器&#xff0c;數據庫&#xff0c;表關系 1.2.3使用案例 1.2.4數據存儲結構 ?編輯 1.3MySQL架構 1.4SQL分類 1.5存儲引擎 1.5.1什么是存儲引擎 1.5.2查看存儲引擎 ?編輯 1.5.3存儲引擎…

CKPT文件是什么?

檢查點&#xff08;Checkpoint&#xff0c;簡稱ckpt&#xff09;是一種用于記錄系統狀態或數據變化的技術&#xff0c;廣泛應用于數據庫管理、機器學習模型訓練、并行計算以及網絡安全等領域。以下將詳細介紹不同領域中ckpt檢查點的定義、功能和應用場景。 數據庫中的ckpt檢查點…

Redis的公共操作命令

目錄 1.Key操作命令1.1 keys *1.2 exists <key]>1.3 type <key>1.4 del <key>1.5 unlink <key>1.6 ttl <key>1.7 expire <key> <秒數>1.8 move <key> <index> 2.庫操作命令2.1 select <index>2.2 dbsize2.3 flush…

【LLM】使用MySQL MCP Server讓大模型輕松操作本地數據庫

隨著MCP協議&#xff08;Model Context Protocol&#xff09;的出現&#xff0c;使得 LLM 應用與外部數據源和工具之間的無縫集成成為可能&#xff0c;本章就介紹如何通過MCP Server讓LLM能夠直接與本地的MySQL數據庫進行交互&#xff0c;例如新增、修改、刪除數據&#xff0c;…

【C++】從零實現Json-Rpc框架(2)

目錄 JsonCpp庫 1.1- Json數據格式 1.2 - JsonCpp介紹 ? 序列化接口 ? 反序列化接口 1.3 - Json序列化實踐 JsonCpp使用 Muduo庫 2.1 - Muduo庫是什么 2.2 - Muduo庫常見接口介紹 TcpServer類基礎介紹 EventLoop類基礎介紹 TcpConnection類基礎介紹 TcpClient…

語文常識推翻百年“R完備、封閉”論

?語文常識推翻百年“R完備、封閉”論 黃小寧 李四光&#xff1a;迷信權威等于扼殺智慧。語文常識表明從西方傳進來的數學存在重大錯誤&#xff1a;將無窮多各異數軸誤為同一軸。 復平面z各點z的對應點zk的全體是zk平面。z面平移變換為zk&#xff08;k是非1正實常數&#xf…