【Linux】進程間通信(IPC)——匿名管道

目錄

為什么要進行進程間通信?

匿名管道的具體實現

pipe創建內存級文件形成管道

pipe的簡單使用

匿名管道的四種情況和五種特性

四種情況

五種特性

PIPE_BUF

命令行管道 |

功能代碼:創建進程池


為什么要進行進程間通信?

1.數據傳輸:一個進程需要將它的數據發送給另一個進程,比如我們有兩個進程,一個負責獲取數據,另一個負責處理數據,這時第一個進程就要將獲取到的數據交給第二個進程

2.資源共享:多個進程間共享同樣的資源

3.通知事件:一個進程需要給其他進程發送消息,通知他們發生了某種事件

4.進程控制:有些事件需要完全控制另一個進程,比如我們在使用gdb調試時,gdb就是一個進程,它控制了我們要調試的進程

進程之前是有互相傳遞信息的需求,但是進程之間又是獨立的,一個進程不可能去另一個進程的地址空間中取信息,所以這就要求操作系統去提供一塊交換數據的空間來供進程之間使用

OS提供空間有不同的樣式,這就有了不同的通信方式

1.管道(分為匿名和命名)

2.共享內存

3.消息隊列

4.信號量

那么我們就先來談一談匿名管道

匿名管道的具體實現

在談之前,我們要有一些之前的知識作為理論基礎,就是父進程創建子進程PCB和文件描述符表是要拷貝一份的,并且里邊的值不會進行修改,就相當于淺拷貝;而管理文件的結構體對象不會拷貝。因為前者是跟進程相關的,而后者是跟文件系統相關的。我們把這段話用圖來描述就是這樣的:

通過這樣的操作父子進程就可以看到同一塊文件的緩沖區了,這樣進程就可以讀寫了,但是兩個文件由讀又寫容易發生混亂,所以我們一般關掉一個進程的讀端,關掉另一個進程的寫端,這樣就實現了單向通信,就是因為它是單向通信,就像管道一樣,所以這樣的通信方式就被命名為管道。

pipe創建內存級文件形成管道

我們上面的操作是基于一個實實在在的磁盤文件的,我們必須得這樣嗎?肯定不是的,OS就提供了一個系統調用負責提供一個內存級的文件它沒有名字,只能通過文件描述符來訪問,這個系統調用叫pipe()

它的參數是一個輸出型參數,就是pipe這個函數把內存級文件的讀寫文件描述符放到這個數組中,我們來取來用。

并且,規定0下標放的是r方法,1下標放的是w方法

由上面我們可以看出,匿名管道是只能具有血緣關系的進程之間使用,因為文件描述符表是要靠父進程創建子進程拷貝下來的。

pipe的簡單使用

那么下面我們就寫一段代碼來驗證上面所說的內容,并且演示管道究竟應該如何使用,下面的代碼就是子進程往管道里寫,父進程往管道里讀

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
void writer(int wfd)
{const char *str = "i am child,this is the ";int cnt = 0;char buffer[128] = {0};while (1){snprintf(buffer, sizeof(buffer), "%s%d message", str, cnt);write(wfd, buffer, strlen(buffer));sleep(1);cnt++;}
}
void reader(int rfd)
{while (1){char buffer[1024] = {0};read(rfd, buffer, sizeof(buffer));printf("I am father,I get a message:%s\n", buffer);}
}int main()
{int pipefd[2] = {0};int n = pipe(pipefd);if (n < 0)return 1;pid_t id = fork();if (id == 0){// 子進程負責wclose(pipefd[0]);writer(pipefd[1]);exit(0);}// 父進程負責rclose(pipefd[1]);reader(pipefd[0]);return 0;
}

匿名管道的四種情況和五種特性

有了上面的一些基本使用,下面我們來演示一下管道的四種情況以及說明五種特性

四種情況

第一種:管道中沒有數據,并且子進程不關閉自己的寫端,這時父進程會進行阻塞等待,直到管道中有數據

第二種:子進程一直寫,父進程不讀,但是父進程不關閉讀端,當管道被寫滿時就要進行阻塞等待,直到管道中的數據被讀出去才會繼續寫

我們就讓子進程一次寫一個字符,看看它一共能寫多少個字符

這里printf如果不給換行的話一定要fflush,否則有的打印的東西會在緩沖區中打印不出來

我們可以看到最終是打印到了65536byte,正好是64kb,我們就可以推斷出管道的大小是64kb

第三種:子進程不寫了并且關掉了寫端,這時讀端讀完了管道中的數據后,read的返回值就為0,這時我們就可以人為的退出了,這和第一種情況是不同的第一種情況是阻塞等待

我們讓子進程寫10秒就退出,read返回值為0父進程就退出

第四種:讓寫端一直寫,但是讀端不讀并且關閉讀端,這時的結果就是寫端也會退出,因為沒人讀了寫就沒意義了。

至于說寫端是如何退出的呢?其實是收到了退出信號,我們也可以通過wait的方式來看一下退出信號是什么

我們讓寫端一直寫,讀端讀5秒后退出,然后通過wait的方式獲取子進程(寫端)的退出信號

五種特性

通過上面的一些介紹,我們就可以總結出管道的五種特性

1.自帶同步機制:寫滿了就不寫了,等待讀,等待它們之間的同步,讀不到就不讀了,等待寫

2.具有血緣關系的進程間進行通信

3.pipe是面向字節流的:我可以一個字符一個字符的寫,同時可以一下讀很多個字節,就是說讀的次數和寫的次數之間是沒有關系的,它們是面向管道中的數據的

4.進程退出,管道自動釋放,文件的生命周期是隨著進程的

5.管道只能單向通信,就是一個寫,一個讀,這也叫半雙工

PIPE_BUF

PIPE_BUF是一個常量,它是由大小的

就是說:每次寫入管道的字節數如果小于這個值,那么就認為本次寫入是原子的(安全的),就是保證內容是完整的,不會被分割

命令行管道 |

之前我們說的命令 | ,本質上就是這篇博客說的pipe

比如?

就是同時創建三個進程,兩個進程之間創建好管道,第一個進程的輸出當作第二個進程的輸入,第二個進程的輸出當作第三個進程的輸入,最終效果是睡眠三秒

功能代碼:創建進程池

進程池就是一次創建多個進程,然后父進程負責分發任務給各個子進程各個子進程處理完一個任務后還可以處理下一個任務,而不需要創建新的進程,這樣就減少了創建和銷毀進程的開銷。

我們之前寫bash的時候就是有一個任務bash就創建子進程,然后子進程進行進程程序替換,執行完后就退出了。

我們今天寫的呢就是創建子進程后子進程一直等待父進程的命令然后執行任務,執行完任務后繼續等待。

//task.hpp
#include <iostream>
#include <unistd.h>
#include <cstring>
#include <cerrno>
#include <cstdlib>
#include <vector>
#include<ctime>
using namespace std;typedef void(*task)();
void task1()
{cout<<"do task one successfully"<<endl;
}
void task2()
{cout<<"do task two successfully"<<endl;
}void task3()
{cout<<"do task three successfully"<<endl;
}
task tasks[3]={task1,task2,task3};//processpool.cc
#include "task.hpp"void Usage(char *argv)
{cout << "please input : " << argv << " and processnum\n";
}
enum error
{USAGE_failed = 1,PIPE_failed,
};class channel
{
public:channel(int wfd, int id, int n): _wfd(wfd), _id(id), _name("channel-" + to_string(n)){}void print(){cout << "name is " << _name << "id is " << _id << "  wfd is " << _wfd << endl;}int wfd(){return _wfd;}~channel() {}private:int _wfd;pid_t _id;string _name;
};class processpool
{
public:processpool(int size): _size(size){for (int i = 1; i <= size; i++){int pipefd[2] = {0};int ret = pipe(pipefd);if (ret == -1){cout << "pipe failed : errno is " << errno << "error describe is " << strerror(errno) << endl;exit(PIPE_failed);}pid_t id = fork();if (id == 0){// 子進程for (int j = pipefd[0] + 1; j <= pipefd[1]; j++){close(j);}// 等待任務while (1){int buffer = 0;int n = read(pipefd[0], &buffer, sizeof(buffer));if (n != 0){cout << "child" << i << " " << getpid() << " "; tasks[buffer]();//執行任務}if (n == 0)break;}exit(0);}channels.push_back({pipefd[1], id, i});close(pipefd[0]);}}void print(){for (auto &e : channels){e.print();}}void get_wfd(vector<int> &f){for (auto &e : channels){f.push_back(e.wfd());}}private:vector<channel> channels;int _size;
};
void give_task(vector<int> &wfd)
{int n = wfd.size();for (int i = 0; i < 100; i++){int tasknum = rand() % (sizeof(tasks) / sizeof(tasks[0]));write(wfd[i % n], &tasknum, sizeof(tasknum));//按順序選擇管道,派發隨機任務sleep(1);}
}int main(int argc, char *argv[])
{srand((unsigned int)time(nullptr));if (argc != 2){Usage(argv[0]);return USAGE_failed;}int processnum = stoi(argv[1]);processpool pool(processnum);//創建進程池vector<int> wfd;pool.get_wfd(wfd);//都可以去給哪個文件描述符給任務give_task(wfd);//發送任務return 0;
}

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

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

相關文章

第五天安全筆記(持續更新)

第五天防御筆記 NAT種類&#xff1a; 靜態NAT動態NATNapt 特點&#xff1a; 一對多----easy ip 多對多的napt 服務器的映射關系: 1.源NAT----基于IP地址進行轉換&#xff0c;包括靜態NAT&#xff0c;動態NAT&#xff0c;以及NAPT 2.目標NAT---基于目標IP地址進行轉換&a…

[筆記.AI]AI Agent理解(LLM AI Agent)

前幾天看到一個圖&#xff0c;感覺能幫助理解 AI Agent 的基本思想和原理&#xff0c;特摘過來備忘。順道加上自己目前對相關部分的理解&#xff0c;不一定對&#xff0c;權當做個記錄。 另外&#xff0c;專門查了下圖的來源&#xff0c;應該是源自 Lilian Weng 的博客文章《…

Android Studio啟動報錯:The emulator process for AVD Pixel_5_API_30 has terminated

Android Studio啟動AVD報錯&#xff1a; The emulator process for AVD Pixel_5_API_30 has terminated. 原因&#xff1a;安裝時使用自定義安裝后&#xff0c;修改了默認安裝目錄。 而avd文件默認在 C:\Users\用戶名\.android 目錄下。所以導致打開AVD時報錯。 解決方法&am…

SadTalker數字人服務器部署

一、單獨SadTalker部署 git clone https://github.com/OpenTalker/SadTalker.gitcd SadTalker conda create -n sadtalker python3.8conda activate sadtalkerpip install torch1.12.1cu113 torchvision0.13.1cu113 torchaudio0.12.1 --extra-index-url https://download.pyto…

切換node版本

一、在Linux上切換Node.js版本有多種實現方法&#xff1a; 1.使用nvm&#xff08;Node Version Manager&#xff09;&#xff1a; 安裝nvm&#xff1a;可以通過curl或wget來安裝nvm&#xff0c;具體請參考nvm的官方文檔。 安裝不同版本的Node.js&#xff1a;使用nvm可以輕松…

快速上手綠聯私有云UGOS Pro系統Docker | 安裝/部署/管理/docker-compose一網打盡

快速上手綠聯私有云UGOS Pro系統Docker | 安裝/部署/管理/docker-compose一網打盡 哈嘍小伙伴們好&#xff0c;我是Stark-C~ 因為眾所周知的原因&#xff0c;關于最新發布的綠聯私有云UGOS Pro系統咱這里也不過多說&#xff0c;不過有一點不可否認&#xff1a;新系統專業性更…

用python寫一個基于ai agent協同供應鏈管理流程的案例

要實現一個基于AI Agent的協同供應鏈管理流程&#xff0c;我們可以參考以下步驟&#xff1a; 1. 首先&#xff0c;定義一個類SupplyChainManager&#xff0c;用于模擬供應鏈管理系統的功能。 python class SupplyChainManager: def __init__(self): self.warehouse Warehous…

代碼隨想錄第51天|單調棧

42. 接雨水 參考 思路1: 暴力解法 找每個柱子的左右高度超時 O(N^2) 思路2: 雙指針優化 class Solution { public:int trap(vector<int>& height) {vector<int> lheight(height.size(), 0);vector<int> rheight(height.size(), 0);lheight[0] hei…

nginx的正向與反向代理

正向代理與反向代理的區別 雖然正向代理和反向代理都涉及代理服務器接收客戶端請求并向服務端轉發請求&#xff0c;但它們之間存在一些關鍵的區別&#xff1a; 正向代理&#xff1a; 在正向代理中&#xff0c;代理服務器代表客戶端向服務器發送請求&#xff0c;并將服務…

ctfshow-web入門-php特性(web104-web108)

目錄 1、web104 2、web105 3、web106 4、web107 5、web108 1、web104 需要傳入的 v1 和 v2 進行 sha1 加密后相等。 解法1&#xff1a; 這里都沒有判斷 v1 和 v2 是否相等&#xff0c;我們直接傳入同樣的內容加密后肯定也一樣。 ?v21 post&#xff1a; v11 拿到 flag…

SQL 多變關聯使用子查詢去重

不去重狀態 select a.*,b.recon_amt from free_settlement_first aleft join free_settlement_second b on a.settlement_first_id b.settlement_first_id 有2條數據出現了重復 使用子查詢去重 select a.*,b.recon_amt from free_settlement_first aleft join free_settlem…

Vue 最新動態!!!

大家好,我是CodeQi! 一位熱衷于技術分享的碼仔。 當Vue 3.4在六個月前發布時,整個前端開發社區都為之振奮。這次更新不僅帶來了許多新特性,還解決了許多開發過程中遇到的痛點。 然而,時間飛逝,隨著我在項目中不斷應用這些新特性,逐漸積累了很多寶貴的經驗和心得。 今…

一篇學通Axios

Axios 是一個基于 Promise 的 HTTP 客戶端&#xff0c;用于瀏覽器和 node.js 環境。它提供了一種簡單易用的方式來發送 HTTP 請求&#xff0c;并支持諸如請求和響應攔截、轉換數據、取消請求以及自動轉換 JSON 數據等功能。 Axios 名字的由來 Axios 的名字來源于希臘神話中的…

Linux操作系統入門(適用java軟件開發)

1.什么是操作系統? 操作系統&#xff08;Operating System&#xff0c;簡稱 OS&#xff09;是一種系統軟件&#xff0c;它管理和控制計算機硬件與軟件資源&#xff0c;為用戶和應用程序提供一個接口和環境來訪問計算機系統的服務和功能。操作系統的主要目標是提供一個方便、有…

探索性數據分析:使用Python與Pandas庫實現數據洞察

探索性數據分析&#xff1a;使用Python與Pandas庫實現數據洞察 引言 在當今數據驅動的時代&#xff0c;數據分析已成為決策制定、策略規劃和業務優化的關鍵環節。無論是商業智能、金融分析還是市場研究&#xff0c;數據分析都扮演著至關重要的角色。Pandas庫作為Python生態系統…

微積分-導數8(線性近似和微分)

線性近似 我們已經看到&#xff0c;在切點附近&#xff0c;曲線與其切線非常接近。事實上&#xff0c;通過放大可微函數圖上的某一點&#xff0c;我們注意到圖形看起來越來越像它的切線&#xff08;見圖&#xff09;。這一觀察是找到函數近似值的方法的基礎。 這個想法是&am…

Java [ 進階 ] JVM雙親委派機制?

目錄 ?探索Java進階 雙親委派機制? 理解 Java 的雙親委派機制 什么是雙親委派機制&#xff1f; 類加載器的層次結構 雙親委派機制的工作原理 優缺點分析 優點 缺點 一些面試題目&#xff1a; 什么是雙親委派機制&#xff1f; 雙親委派機制的工作流程是怎樣的&am…

monodepth代碼與原理對照實現

先實現demomonodepth/monodepth_simple.py at master mrharicot/monodepth GitHub import os os.environ[TF_CPP_MIN_LOG_LEVEL]0 這行代碼是為tensorflow設置環境變量TF_CPP_MIN_LOG_LEVEL,用來控制tensorflow c后端輸出的日志級別。0就是輸出所有級別的日志信息。包括(調…

vue2學習筆記3 - 開發環境知識補充:live server簡介

學習筆記1搭建開發環境中&#xff0c;在vs code里安裝了live server插件&#xff0c;后續多次使用open with live server來打開瀏覽器&#xff0c;展示代碼運行效果。本著知其然也要知其所以然的態度&#xff0c;稍稍了解了一下Live server。 什么是Live Server Live Server是…

探索Conda的依賴迷宮:包依賴樹的構建與解析

探索Conda的依賴迷宮&#xff1a;包依賴樹的構建與解析 引言 在復雜的軟件項目中&#xff0c;依賴管理是確保軟件正常運行的關鍵。Conda作為流行的Python包管理器&#xff0c;提供了強大的依賴樹功能&#xff0c;幫助用戶理解和管理包依賴關系。本文將詳細介紹如何在Conda中使…