【Linux】匿名管道+進程池


文章目錄

  • 前置知識
  • 一、管道的原理
  • 二、管道的特性
  • 三、管道的接口
  • 四、使用管道實現簡單的進程池
    • 解決進程池的一個小問題


前置知識

一個進程在創建時,會默認打開三個文件,分別是:stdin,stdout,stderr
進程中有一個維護進程所打開的文件的文件描述對象結構體struct files_struct該文件描述對象結構體中包含一個fd_array,文件描述符表,這個文件描述符表存儲的是對應打開的文件的文件描述對象的地址。也就是說,每一個文件都有對應的文件對象,來記錄該文件的各種屬性struct file。而進程對應的是文件描述對象,兩者不同。
在這里插入圖片描述
fd_array中存儲的就是struct file*類型。

默認打開的三個文件中,stdin,stdout,stderr對應的分別是鍵盤文件,顯示器文件,顯示器文件,占用了fd_array文件描述符表中的0,1,2下標。

所以,進程再次創建文件時,會默認從3號下標開始記錄。

一、管道的原理

在這里插入圖片描述

父進程創建管道文件時,默認打開讀端和寫端,讀端的文件fd存在3號下標中,寫端文件存在4號下標中。
子進程被創建時會繼承父進程的管理文件的對象,所以子進程的fd_array的3號和4號下標也記錄了管道文件的讀寫端。

為了保證父子進程之間的通信,假設是父進程進行讀取,子進程進行寫入。
所以需要關閉父進程的寫端,關閉子進程的讀端。

在這里插入圖片描述
子進程進行寫入,父進程進行讀取,就能實現通信了。

問題:為什么父進程不直接把要發送給子進程的數據保存一份,子進程在創建時就會繼承這份數據了。

這種通信方式不是不可以,但只能靜態通信。


實際上,在創建管道文件時,會創建兩個文件對象,它們存儲同一個inode,指向同一塊緩沖區,這樣就能實現子進程通過寫端的struct file和父進程的讀端的struct file進而看到同一個文件緩沖區,也就是讓不同的進程看到同一份資源。

所以管道通信只能進行單向通信!!!

在這里插入圖片描述

二、管道的特性

Linux中,管道的大小一般是4096字節(4KB)

管道的本質就是內存級文件。

  • 1.進程之間使用管道通信,必須具有血緣關系。常用于父子關系。
  • 2.管道通信只能進行單向通信。
  • 3.管道是基于文件的,而文件是隨進程的,所以管道的生命周期隨進程。
  • 4.這個管道文件,沒有路徑,沒有名字,更沒有inode,因為使用該管道文件,是由操作系統創建并管理的,而父子進程之間通過該管道進行通信的原因是繼承,所以該管道就叫做匿名管道。
  • 5.父子進程是會進行進程協同,同步與互斥的。我的理解是:父子進程要向管道文件中讀寫內容,就要調用write和read系統調用,而該函數會進行阻塞地等待或讀取。
    • 由此可知,管道的讀寫中有4種情況:
    • 1.讀寫端正常,如果管道為空,讀端就要阻塞。
    • 2.讀寫端正常,如果管道被寫滿了,寫端就要阻塞。
    • 3.讀端正常讀,寫端關閉,讀端就會讀到0,表明讀到了文件結尾,不會被阻塞。
    • 4.寫端正常寫,讀端關閉,寫端不會再寫了,沒有意義了,因為沒人讀。

操作系統所做的這一切,本質就是讓不同的進程看到同一份資源。

三、管道的接口

在這里插入圖片描述
該系統接口的參數是一個數組,數組有兩個元素,記錄的就是打開的管道文件的讀端和寫端在fd_array中的位置。

所以我們只需要傳一個數組過去即可。

如果成功返回0,失敗返回-1,且錯誤碼被設置。

所以該參數叫做輸出型參數

因為會把用戶傳進來的參數進行設置修改,所以用戶可以再次使用該參數。

使用方法:

#define SIZE 2
int pipefd[SIZE] = {0};
int n = pipe(pipefd);

這是父進程申請管道文件,父進程需要讀取,所以關閉寫端

clode(pipefd[1]);

附帶的一個函數:
在這里插入圖片描述
printf函數我們熟悉,向顯示器中打印格式化內容。
snprintf函數是printf函數的變形,本應該向顯示器文件中打印的內容,變成向str指針指向的文件中打印size大小的格式化內容。

snprintf(buffer,sizeof(buffer),"%s-%d-%d",s.c_str(),self,cnt);

匿名管道的測試代碼

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cerrno>#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>#define SIZE 2
#define NUM 1024
using namespace std;// 1.先創建管道文件
// 2.創建子進程
// 3.子進程進行寫入,父進程進行讀取//向指定文件描述符對應文件寫入
void Write(int wfd)
{string s = "Hello , i am child";char buffer[NUM];//getline(cin,buffer);pid_t self = getpid();int cnt = 5;while(cnt--){buffer[0] = 0; // 告訴讀者我的buffer當作字符串來用snprintf(buffer,sizeof(buffer),"%s-%d-%d",s.c_str(),self,cnt);  cout << buffer << endl;write(wfd,buffer,strlen(buffer));sleep(1);}}void Read(int rfd)
{char buffer[NUM];while(true){buffer[0] = 0;ssize_t n = read(rfd,buffer,sizeof(buffer));//n是讀取到的個數if(n > 0) {buffer[n] = '\0';cout << "father-" << getpid() <<  "get a message from child:[" << buffer << "]#" << endl;}else if(n == 0){cout << "father read file done!" << endl;break;}else break;sleep(1);}
}int main()
{int pipefd[SIZE] = {0};int n = pipe(pipefd);//成功返回0,失敗返回-1if (n < 0) // 管道創建失敗{perror("pipefd fail");return 1;}// 管道創建成功cout << "pipefd[0] : " << pipefd[0] <<  " pipefd[1] : " << pipefd[1] << endl; //創建子進程pid_t id = fork();if (id < 0){perror("fork fail");return 2;}// child : writeelse if (id == 0){//關閉讀端close(pipefd[0]);//寫入Write(pipefd[1]);//寫入完成關閉寫端close(pipefd[1]);exit(1);}// father : readclose(pipefd[1]);Read(pipefd[0]);int status = 0;pid_t rid = waitpid(id,&status,0); // 阻塞等待if(rid < 0)return 3;else if(rid > 0)cout << "wait child process success!" << endl;close(pipefd[0]);return 0;
}

四、使用管道實現簡單的進程池

進程池:一個父進程通過創建多個子進程,然后將不同的任務派發給不同的進程,從而提高工作效率。

相比于接到一個任務后,再創建子進程,然后再將該任務交給子進程去做。

進程池的方法是一次創建多個子進程來待命,只要有任務,就可以立即派發,多個任務也能實現并行。

在這里插入圖片描述

而父進程與子進程實現通信的方式就是管道通信

進程池代碼

解決進程池的一個小問題

在父進程創建子進程時,子進程會繼承父進程的struct files_struct,所以在創建第二個子進程時,由于它繼承了父進程的信息,導致第二個子進程有能力去修改父進程與第一個子進程進行通信的管道文件。

所以在父進程不斷創建子進程的過程中,子進程的fd_array空間被占用越來越多,意味著后面的子進程能修改前面的管道文件。

在這里插入圖片描述

解決辦法,在父進程創建第二個子進程開始,把該子進程中指向第一個管道文件的寫端全部關閉。


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

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

相關文章

1linux

Is查看目錄內容 ls -ahil a表示全部&#xff0c;h表示文件大小以人類易讀的形式給出&#xff0c;i表示索引節點&#xff0c;l表示長列表形式。 cd 切換目錄 touch 創建文件 mkdir 創建目錄 mkdir Makedirectory&#xff0c;創建目錄&#xff0c;-p指定路徑&#xff0c;-m指定權…

炫我出席數字光影工作室專業建設論壇,受聘為專家委員會委員!

11月18日&#xff0c;炫我科技受邀參加在北京深瀾AI空間舉辦的2023數字光影工作室專業建設論壇。本次活動由北京市新媒體技師學院主辦、北京瀾景科技有限公司協辦&#xff0c;私有云售前技術工程師龔琛代表我司出席&#xff0c;并受聘為新媒體技師學院數字光影工作室專家委員會…

Mysql基礎操作(命令行)

文章目錄 Mysql基礎操作&#xff08;命令行&#xff09;背景創建數據庫選擇數據庫查看所有表查看表結構向表插入數據插入第一條插入第二條插入第三條 查詢表數據修改表數據刪除表數據 Mysql基礎操作&#xff08;命令行&#xff09; 背景 docker安裝mysql8&#xff0c;映射本地…

ubuntu下,PX4使用 upload 下載代碼沒反應

可能原因&#xff0c;沒有串口權限 sudo chmod 777 /dev/ttyACM0開啟串口權限&#xff0c;本次問題解決。

GTC2023全球流量大會蓄勢待發,菊風在7B57展位等你!

第六屆 GTC 全球流量大會&#xff08;以下簡稱 GTC2023&#xff09;將于12月5日- 6日&#xff0c;在深圳福田會展中心7&#xff06;8號館舉辦。 據悉&#xff0c;本屆大會將是歷屆以來規模最大、參與人數最多、跨境出海資源最豐富的一次行業盛會。7、8 號館共 15000 平方米&am…

計算機組成原理-磁盤存儲器

文章目錄 總覽外存儲器磁盤存儲器磁盤的性能指標磁盤地址磁盤的工作過程磁盤陣列 總結 總覽 外存儲器 磁盤存儲器 寫是利用電流產生磁場從而寫磁盤 讀是利用載磁體移動時產生的電場從而得到數據 磁性材質易受外界磁場干擾 下圖中 載磁體上N S的前后順序代表對應存儲二進制的比…

【深度學習】卷積神經網絡(CNN)的參數優化方法

著名&#xff1a; 本文是從 Michael Nielsen的電子書Neural Network and Deep Learning的深度學習那一章的卷積神經網絡的參數優化方法的一些總結和摘錄&#xff0c;并不是我自己的結論和做實驗所得到的結果。我想Michael的實驗結果更有說服力一些。本書在github上有中文翻譯的…

【不同請求方式在springboot中對應的注解】

GET 請求方法&#xff1a;用于獲取資源。使用 GetMapping 注解來處理 GET 請求。 示例代碼&#xff1a; RestController public class MyController {GetMapping("/resource")public ResponseEntity<String> getResource() {// 處理 GET 請求邏輯} }POST 請求方…

喜訊!云起無垠成為國家信息安全漏洞庫(CNNVD)技術支撐單位

近日&#xff0c;云起無垠憑借其在漏洞挖掘、漏洞檢測以及漏洞修復等領域的卓越表現&#xff0c;榮獲“國家信息安全漏洞庫&#xff08;CNNVD&#xff09;技術支撐單位等級證書&#xff08;三級&#xff09;”&#xff0c;正式成為CNNVD技術支撐單位。 中國國家信息安全漏洞庫&…

MTK聯發科MT6762/MT6763/MT6765安卓核心板參數規格比較

MT6762安卓核心板 MTK6762安卓核心板是一款工業級高性能、可運行 android9.0 操作系統的 4G智能模塊。 CPU&#xff1a;4xCortex-A53 up to 2.0Ghz/4xCortex-A53 up to 1.5GhzGraphics&#xff1a;IMG GE8320 Up to 650MhzProcess&#xff1a;12nmMemory&#xff1a;1xLP3 9…

【正點原子STM32連載】 第六十章 串口IAP實驗(Julia分形)實驗 摘自【正點原子】APM32F407最小系統板使用指南

1&#xff09;實驗平臺&#xff1a;正點原子APM32F407最小系統板 2&#xff09;平臺購買地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套實驗源碼手冊視頻下載地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html## 第六十…

CMake使用file(GLOB ...)需要注意的問題

文章目錄 基本語法使用例子潛在的問題大型項目中推薦的用法 file(GLOB ...) 命令用于獲取匹配指定模式的文件列表。在 CMake 中&#xff0c;file(GLOB ...) 命令的一種常見用法是用于收集源文件列表&#xff0c;例如 C 源文件&#xff08;.cpp&#xff09;和 C 源文件&#xff…

html頁面加載json數據,在html中顯示JSON數據的方法

html頁面加載json數據,在html中顯示JSON數據的方法 export const mixin {methods: {syntaxHighlight(json) {if (typeof json ! string) {json JSON.stringify(json, undefined, 2);}json json.replace(/&/g, &).replace(/</g, <).replace(/>/g, >);re…

實例分割12篇頂會論文及代碼合集,含2023最新

同學們&#xff0c;你們覺得視覺經典四個任務中哪個最難&#xff1f;我個人覺得是實例分割。 因為它既具備語義分割的特點&#xff0c;需要做到像素層面上的分類&#xff0c;也具備目標檢測的一部分特點&#xff0c;即需要定位出不同實例&#xff0c;即使它們是同一種類。 但…

LangChain的函數,工具和代理(一):OpenAI的函數調用

一、什么是函數調用功能 幾個月前OpenAI官方發布了其API的函數調用功能(Function calling), 在 API 調用中&#xff0c;您可以描述函數&#xff0c;并讓模型智能地選擇輸出包含調用一個或多個函數的參數的 JSON 對象。API函數“ChatCompletion” 雖然不會實際調用該函數&#…

C語言變量和常量

變量和常量 標識符 在計算機高級語言中&#xff0c;用來對變量、符號常量、函數、數組、類型等命名的有效字符序列統稱為標識符&#xff08;identifier&#xff09;。 C語言規定標識符&#xff1a; 只能由字母&#xff0c;數字和下劃線組成。不能以數字開頭。字母區分大小寫…

一站式企業快遞管理平臺使用教程

因公寄件在企業中重要性的提升&#xff0c;催生出了企業快遞管理平臺。為什么這么說呢&#xff1f; 隨著經濟和快遞行業的發展&#xff0c;因公寄件在企業中成了一件“常事”&#xff0c;寄文件合同、發票、節假日慰問品、樣品等等&#xff0c;這種情況之下&#xff0c;因公寄件…

Vue3 設置點擊后滾動條移動到固定的位置

需求&#xff1a; 點擊不通過按鈕&#xff0c;顯示紅框中表單&#xff0c;且滾動條滾動到底部 &#xff08;顯示紅框中表單默認不顯示&#xff09; <el-button click"onApprovalPass">不通過</el-button> <div class"item" v-if"app…

vue打包優化

vue.config.js文件中 module.exports defineConfig({ productionSourceMap: false,//去掉mapjs文件 });