Linux進程通信入門:匿名管道的原理、實現與應用場景

Linux系列


文章目錄

  • Linux系列
  • 前言
  • 一、進程通信的目的
  • 二、進程通信的原理
    • 2.1 進程通信是什么
    • 2.2 匿名管道通訊的原理
  • 三、進程通訊的使用
  • 總結


前言

Linux進程間同通訊(IPC)是多個進程之間交換數據和協調行為的重要機制,是我們學習Linux操作系統中比較重要的一個模塊。


一、進程通信的目的

Linux 進程間通信(IPC)的主要目的是讓多個獨立的進程能夠協作、共享資源、交換數據或同步操作。這是現代操作系統中多任務、并行計算和分布式系統的核心基礎。以下是具體的目的和場景:

  • 數據傳輸:一個進程需要將它的數據發送給另一個進程
  • 協同工作:兩進程需要更具對方的執行結果來協同完成某種任務
  • 資源同步與互斥:避免多個進程同時訪問共享資源導致數據競爭或狀態不一致

二、進程通信的原理

2.1 進程通信是什么

進程通信的本質其實就是多個進程可以同時訪問同一份“資源”。對于進程來說“資源”就是空間中存儲的數據,所以要實現進程通信我們只需要讓多個進程可以同時訪問同一塊空間即可。這里我們就以兩個進程為例:
在這里插入圖片描述
這時我們只需要做到讓進程1向這塊空間中寫數據,進程2可以將進程1寫入的數據從空間中取出,這樣就完成了通訊工作。那么這塊空間該由誰提供呢?由于進程必須保證獨立性(也就是說不論這個空間由哪個進程提供,另一個進程都不能對它訪問,否則就破壞了獨立性),也就注定了這塊共享空間只能由第三方提供---------操作系統,那么這塊空間就必須由操作系統管理了,空間的創建到釋放都是由操作系統來完成的,所以我們對這塊空間的訪問,就變成了對操作系統的訪問,而進程(代表用戶)要想訪問操作系統,只能通過系統調用接口進行。
為了滿足通訊需求,一般操作系統都會有一個獨立的通信模塊。今天我們就來介紹基于文件級別的通訊方式------管道

2.2 匿名管道通訊的原理

根據上面的分析,我們首先要讓兩個進程看到同一份資源:

在這里插入圖片描述

我們利用父進程創建子進程時的特點,這樣就可以讓兩個進程(父和子)看到同一分空間,而我們的管道就是文件,它是內核文件,并不會向磁盤刷新內容,父子進程對他進行訪問時并不需要在目錄中查詢,而是直接通過文件描述符查找,所以管道文件不用定義名字,因此被稱為匿名管道。
到了這里我們僅解決了,讓兩個進程看到同一份空間,但是管道文件不支持以讀寫方式打開,也就是說我們上面的介紹,兩個進程(父子進程)只能向管道中讀,或只能向管道中寫,而進程通訊一般為一個進程寫,一個進程讀。

在這里插入圖片描述
所以進程在打開管道文件時,都會分別以讀、寫兩種方式打開,當我們讓父進程讀取數據,子進程寫入數據的形式通訊時(這個用戶自己控制),父進程就關閉對應的寫方式,子進程關閉對應的讀方式,此時子進程就可以向管道文件的緩沖區寫入數據供父進程讀取。到了這里,我們就建立了進程通信的信道。

通過上面的介紹我們可以知道匿名管道通信的特點為:

  • 只能進行單向通信
  • 通信進程間需要有血緣關系,常用于父子

三、進程通訊的使用

首先我們先來認識需要用到的系統調用:

在這里插入圖片描述
這個系統調用需要傳遞一個存儲兩個元素的整形數組,該參數為輸出型參數,第一個元素為以讀形式打開的文件描述符,第二從元素為以寫形式打開的文件描述符。下面我們先實現一個簡單的通信:
示例1:

include<iostream>
#include<unistd.h>
#include<sys/types.h>
#include<string>
#include<cstring>
using namespace std;int main()
{int pipefd[2];int n=pipe(pipefd);if(n<0)return 1;pid_t id=fork();//創建子進程if(id==0)//子進程{string str="Hello father process\n";close(pipefd[0]);//子關閉讀權限write(pipefd[1],str.c_str(),strlen(str.c_str()));//向管道中寫入數據exit(0);}close(pipefd[1]);//父關閉寫權限char tmp[100]={0};read(pipefd[0],tmp,100);//從管道中讀取數據cout<<tmp;return 0;
}

程序執行結果:
在這里插入圖片描述
這給代碼主要幫助我們理解上面介紹的,關閉文件描述符以及pipe()參數的作用。接下來我們會通過下面的代碼示例,對我們的管道通信的四種情況進行總結。

情況1:讀寫端正常,管道為空,讀端就要阻塞

#include<iostream>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<cstdio>
#include<cstring>
using namespace std;#define N 2
#define NUM 1024void Write(int wfd)
{char buff[NUM];string str="Hello ,I am child,pid:";pid_t self=getpid();int num=0;while(true){sleep(2);buff[0]=0;snprintf(buff,sizeof(buff),"%s%d---%d",str.c_str(),self,num++);//將要寫入數據格式化到buffwrite(wfd,buff,strlen(buff));//將buff中的數據寫入管道}
}void Read(int rfd)
{char buff[NUM];while(true){buff[0]=0;int n=read(rfd,buff,sizeof(buff));//從管道中讀取數據if(n>0){cout<<"father get message:"<<buff<<endl;}else if(n==0){cout<<"father read fail"<<endl;}else break;}
}
int main()
{int pipefd[N];int n=pipe(pipefd);if(n<0)return 1;//調用失敗程序返回pid_t id=fork();//創建子進程if(id<0)return 1;if(id==0)//child{close(pipefd[0]);//關閉讀端Write(pipefd[1]);close(pipefd[1]);//這一步有沒有都無所謂exit(0);}//fatherclose(pipefd[1]);//關閉寫端Read(pipefd[0]);close(pipefd[0]);return 0;
}

在這里插入圖片描述
想要的效果不好展示,大家可以自己跑以下看看程序執行過程
上述代碼,子進程在進程在向管道中寫入數據時,每間隔兩秒寫入一次,而父進程會阻塞等待,當子進程寫入完成后父進程才會讀取并返回。我們可以看到程序并沒有執行cout<<"father read fail"<<endl;這也證明了父進程會進行阻塞等待,等待子進程寫入。
個人感覺這已經能說明問題了,不知道你能不能get到

情況二:讀寫端正常,管道被寫滿,寫端就要阻塞
接下來我們對上面代碼進行一點小改動:

void Write(int wfd)
{char buff[NUM];string str="Hello ,I am child,pid:";pid_t self=getpid();int num=0;while(true){buff[0]=0;snprintf(buff,sizeof(buff),"%s%d---%d",str.c_str(),self,num++);//將要寫入數據格式化到buffwrite(wfd,buff,strlen(buff));//將buff中的數據寫入管道cout<<"已經寫入了:"<<num<<"條信息"<<endl;//記錄寫入次數}}
void Read(int rfd)
{char buff[NUM];while(true){buff[0]=0;sleep(10);int n=read(rfd,buff,sizeof(buff));//從管道中讀取數據if(n>0){cout<<"father get message:"<<buff<<endl;}else if(n==0){cout<<"father read fail"<<endl;}else break;}
}

我們讓父進程等待10秒再讀取,子進程一直寫入。
在這里插入圖片描述
此時你會看到當子進程入定數量的數據后,就會停止寫入進入阻塞狀態,等待父進程的讀取,父進程讀取成功后,子進程才能繼續寫入,其原因就直管道被寫滿了。

情況三:讀端正常,寫端關閉,讀端就會讀到0,表明讀到了文件(pipe)結尾,不會阻塞

void Write(int wfd)
{char buff[NUM];string str="Hello ,I am child,pid:";pid_t self=getpid();int num=0;int cnt=5;//寫入五次while(cnt--){sleep(1);buff[0]=0;snprintf(buff,sizeof(buff),"%s%d---%d",str.c_str(),self,num++);//將要寫入數據格式化到buffwrite(wfd,buff,strlen(buff));//將buff中的數據寫入管道}cout<<"我是寫端,我關閉了"<<endl;
}void Read(int rfd)
{char buff[NUM];while(true){buff[0]=0;sleep(1);int n=read(rfd,buff,sizeof(buff));//從管道中讀取數據if(n>0){cout<<"father get message:"<<buff<<endl;}else if(n==0){cout<<"father read fail"<<endl;}else break;}
}

在這里插入圖片描述
這個圖效果就很好了,當寫端關閉時,讀端讀取到文件末尾返回0執行cout<<"father get message:"<<buff<<endl;,子進程退出變為僵尸。

情況四:寫端正常,讀端關閉,操作系統通過信號殺掉正在寫入的進程。

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cstdlib> //stdlib.h
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>#define N 2
#define NUM 1024using namespace std;// child
void Writer(int wfd)
{string s = "hello, I am child";pid_t self = getpid();int number = 0;char buffer[NUM];while (true){sleep(1);// 構建發送字符串buffer[0] = 0; // 字符串清空, 只是為了提醒閱讀代碼的人,我把這個數組當做字符串了snprintf(buffer, sizeof(buffer), "%s-%d-%d", s.c_str(), self, number++);// cout << buffer << endl;// 發送/寫入給父進程, system callwrite(wfd, buffer, strlen(buffer)); // strlen(buffer) + 1???}
}// father
void Reader(int rfd)
{char buffer[NUM];int cnt = 0;while(true){buffer[0] = 0; // system callssize_t n = read(rfd, buffer, sizeof(buffer)); //sizeof != strlenif(n > 0){buffer[n] = 0; // 0 == '\0'cout << "father get a message[" << getpid() << "]# " << buffer << endl;}else if(n == 0) {printf("father read file done!\n");break;}else break;cnt++;if(cnt>5) break;// cout << "n: " << n << endl;}
}int main()
{int pipefd[N] = {0};int n = pipe(pipefd);if (n < 0)return 1;// child -> w, father->rpid_t id = fork();if (id < 0)return 2;if (id == 0){// childclose(pipefd[0]);// IPC codeWriter(pipefd[1]);close(pipefd[1]);exit(0);}// fatherclose(pipefd[1]);// IPC codeReader(pipefd[0]); // 讀取5sclose(pipefd[0]);cout << "father close read fd: " << pipefd[0] << endl;sleep(5); //為了觀察僵尸int status = 0;pid_t rid = waitpid(id, &status, 0);    if(rid < 0) return 3;cout << "wait child success: " << rid << " exit code: " << ((status>>8)&0xFF) << " exit signal: " << (status&0x7F) << endl;sleep(5);cout << "father quit" << endl;return 0;
}

在這里插入圖片描述
在這里插入圖片描述
可以看到當讀端關閉后,操作系統就會將使用13號信號殺掉寫端。

總結

1、具有血緣關系的進程才能使用匿名管道通訊
2、管道只能單向通信
3、父子進程是會進程協同的,同步與互斥的------保護管道文件的數據安全
4、管道是門面向字節流的
5、管道是基于文件的,而文件的生命周期是隨進程的

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

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

相關文章

探秘Transformer系列之(26)--- KV Cache優化 之 PD分離or合并

探秘Transformer系列之&#xff08;26&#xff09;— KV Cache優化 之 PD分離or合并 文章目錄 探秘Transformer系列之&#xff08;26&#xff09;--- KV Cache優化 之 PD分離or合并0x00 概述0x01 背景知識1.1 自回歸&迭代1.2 KV Cache 0x02 靜態批處理2.1 調度策略2.2 問題…

十大PDF解析工具在不同文檔類別中的比較研究

PDF解析對于包括文檔分類、信息提取和檢索在內的多種自然語言處理任務至關重要&#xff0c;尤其是RAG的背景下。盡管存在各種PDF解析工具&#xff0c;但它們在不同文檔類型中的有效性仍缺乏充分研究&#xff0c;尤其是超出學術文檔范疇。通過使用DocLayNet數據集&#xff0c;比…

HarmonyOS-ArkUI 裝飾器V2 @ObservedV2與@Trace裝飾器

參考文檔: 文檔中心https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V14/arkts-new-observedv2-and-trace-V14#trace%E8%A3%85%E9%A5%B0%E5%AF%B9%E8%B1%A1%E6%95%B0%E7%BB%84由于V2的裝飾器比V1的裝飾器更加易用,盡管學習的過程中用到的都是V1的裝飾器,但…

GPT - GPT(Generative Pre-trained Transformer)模型框架

本節代碼主要為實現了一個簡化版的 GPT&#xff08;Generative Pre-trained Transformer&#xff09;模型。GPT 是一種基于 Transformer 架構的語言生成模型&#xff0c;主要用于生成自然語言文本。 1. 模型結構 初始化部分 class GPT(nn.Module):def __init__(self, vocab…

基于FPGA的六層電梯智能控制系統 矩陣鍵盤-數碼管 上板仿真均驗證通過

基于FPGA的六層電梯智能控制系統 前言一、整體方案二、軟件設計總結 前言 本設計基于FPGA實現了一個完整的六層電梯智能控制系統&#xff0c;旨在解決傳統電梯控制系統在別墅環境中存在的個性化控制不足、響應速度慢等問題。系統采用Verilog HDL語言編程&#xff0c;基于Cyclo…

車載通信系統中基于ISO26262的功能安全與抗輻照協同設計研究

摘要&#xff1a;隨著智能網聯汽車的快速發展&#xff0c;車載通信系統正面臨著功能安全與抗輻照設計的雙重挑戰。在高可靠性要求的車載應用場景下&#xff0c;如何實現功能安全標準與抗輻照技術的協同優化&#xff0c;構建滿足ISO26262安全完整性等級要求的可靠通信架構&#…

Node.js種cluster模塊詳解

Node.js 中 cluster 模塊全部 API 詳解 1. 模塊屬性 const cluster require(cluster);// 1. isMaster // 判斷當前進程是否為主進程 console.log(是否為主進程:, cluster.isMaster);// 2. isWorker // 判斷當前進程是否為工作進程 console.log(是否為工作進程:, cluster.isW…

融合動態權重與抗刷機制的網文評分系統——基于優書網、IMDB與Reddit的混合算法實踐

? Yumuing 博客 &#x1f680; 探索技術的每一個角落&#xff0c;解碼世界的每一種可能&#xff01; &#x1f48c; 如果你對 AI 充滿好奇&#xff0c;歡迎關注博主&#xff0c;訂閱專欄&#xff0c;讓我們一起開啟這段奇妙的旅程&#xff01; 以權威用戶為核心&#xff0c;時…

使用Golang打包jar應用

文章目錄 背景Go 的 go:embed 功能介紹與打包 JAR 文件示例1. go:embed 基礎介紹基本特性基本語法 2. 嵌入 JAR 文件示例項目結構代碼實現 3. 高級用法&#xff1a;嵌入多個文件或目錄4. 使用注意事項5. 實際應用場景6. 完整示例&#xff1a;運行嵌入的JAR 背景 想把自己的一個…

前端大屏可視化項目 局部全屏(指定盒子全屏)

需求是這樣的&#xff0c;我用的項目是vue admin 項目 現在需要在做大屏項目 不希望顯示除了大屏的其他東西 于是想了這個辦法 至于大屏適配問題 請看我文章 底部的代碼直接復制就可以運行 vue2 px轉rem 大屏適配方案 postcss-pxtorem-CSDN博客 <template><div …

《2025藍橋杯C++B組:D:產值調整》

**作者的個人gitee**?? 作者的算法講解主頁?? 每日一言&#xff1a;“淚眼問花花不語&#xff0c;亂紅飛過秋千去&#x1f338;&#x1f338;” 題目 二.解題策略 本題比較簡單&#xff0c;我的思路是寫三個函數分別計算黃金白銀銅一次新產值&#xff0c;通過k次循環即可獲…

[VTK] 四元素實現旋轉平移

VTK 實現旋轉&#xff0c;有四元數的方案&#xff0c;也有 vtkTransform 的方案&#xff1b;主要示例代碼如下&#xff1a; //構造旋轉四元數vtkQuaterniond rotation;rotation.SetRotationAngleAndAxis(vtkMath::RadiansFromDegrees(90.0),0.0, 1.0, 0.0);//構造旋轉點四元數v…

華為hcie證書的有效期怎么判斷?

在ICT行業&#xff0c;華為HCIE證書堪稱含金量極高的“敲門磚”&#xff0c;擁有它往往意味著在職場上更上一層樓。然而&#xff0c;很多人在辛苦考取HCIE證書后&#xff0c;卻對其有效期相關事宜一知半解。今天&#xff0c;咱們就來好好嘮嘮華為HCIE證書的有效期怎么判斷這個關…

【精品PPT】2025固態電池知識體系及最佳實踐PPT合集(36份).zip

精品推薦&#xff0c;2025固態電池知識體系及最佳實踐PPT合集&#xff0c;共36份。供大家學習參考。 1、中科院化學所郭玉國研究員&#xff1a;固態金屬鋰電池及其關鍵材料.pdf 2、中科院物理所-李泓固態電池.pdf 3、全固態電池技術研究進展.pdf 4、全固態電池生產工藝.pdf 5、…

MySQL 中為產品添加靈活的自定義屬性(如 color/size)

方案 1&#xff1a;EAV 模型&#xff08;最靈活但較復雜&#xff09; 適合需要無限擴展自定義屬性的場景 -- 產品表 CREATE TABLE products (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(100),price DECIMAL(10,2) );-- 屬性名表 CREATE TABLE attributes (id INT PRIMA…

CSPM認證對項目論證的范式革新:從合規審查到價值創造的戰略躍遷

引言 在數字化轉型浪潮中&#xff0c;全球企業每年因項目論證缺陷導致的損失高達1.7萬億美元&#xff08;Gartner 2023&#xff09;。CSPM&#xff08;Certified Strategic Project Manager&#xff09;認證體系通過結構化方法論&#xff0c;將傳統的項目可行性評估升級為戰略…

CLIP中的Zero-Shot Learning原理

CLIP&#xff08;Contrastive Language-Image Pretraining&#xff09;是一種由OpenAI提出的多模態模型&#xff0c;它通過對比學習的方式同時學習圖像和文本的表示&#xff0c;并且能在多種任務中進行零樣本學習&#xff08;Zero-Shot Learning&#xff09;。CLIP模型的核心創…

spring mvc 中 RestTemplate 全面詳解及示例

RestTemplate 全面詳解及示例 1. RestTemplate 簡介 定義&#xff1a;Spring 提供的同步 HTTP 客戶端&#xff0c;支持多種 HTTP 方法&#xff08;GET/POST/PUT/DELETE 等&#xff09;&#xff0c;用于調用 RESTful API。核心特性&#xff1a; 支持請求頭、請求體、URI 參數的…

北大:LLM在NL2SQL中任務分解

&#x1f4d6;標題&#xff1a;LearNAT: Learning NL2SQL with AST-guided Task Decomposition for Large Language Models &#x1f310;來源&#xff1a;arXiv, 2504.02327 &#x1f31f;摘要 &#x1f538;自然語言到SQL&#xff08;NL2SQL&#xff09;已成為實現與數據庫…

STM32LL庫編程系列第八講——ADC模數轉換

系列文章目錄 往期文章 STM32LL庫編程系列第一講——Delay精準延時函數&#xff08;詳細&#xff0c;適合新手&#xff09; STM32LL庫編程系列第二講——藍牙USART串口通信&#xff08;步驟詳細、原理清晰&#xff09; STM32LL庫編程系列第三講——USARTDMA通信 STM32LL庫編程…