Linux管道

預備知識:

進程通信

進程需要某種協同,協同的前提條件是通信。有些數據是用來通知就緒的,有些是單純的傳輸數據,還有一些是控制相關信息。

進程具有獨立性,所以通信的成本可能稍微高一點;進程間通信前提是讓不同進程看到同一份(操作系統)資源(“一段內存”)。

一定是某一個進程先需要通信,讓OS創建一個共享資源,OS必須提供很多系統調用,OS創建的共享資源不同,系統調用不同,進程通信就會有不同種類。

System V

System V是一套本地通信的標準,通信方式有:

1.消息隊列

2.共享內存

3.信息量

直接復用內核代碼直接通信:命名管道和匿名管道。

管道

匿名管道

父子進程的文件表類似于淺拷貝,不會創建第二份struct file;進程會默認打開標準輸入輸出,就是拷貝了bash的files_struct,繼承了它的文件描述符;struct file內部也包含了引用計數(內存級),因此子進程fd關閉不影響父進程文件使用。

在這里,父子進程看到同一份資源(內核級緩沖區),這個資源叫管道文件,父進程從緩沖區讀,子進程緩沖區寫,就能進行通信,當然,這里的管道通信是單向的。

讓父子進程關掉不需要的描述符,緩沖區不需要刷新,因為不需要寫到磁盤文件,而且寫入效率也低。

創建管道文件

如果想要雙向通信,可以創建兩個管道,單項通信更簡單一些,如果在一個緩沖區雙方都要讀寫,那么會更復雜。

代碼:

#include<iostream>
#include<unistd.h>
#include<cstring>
using namespace std;
void wrprc(int fd)
{string s = "syx 666";int ct = 0;int id = getpid();while (1){string message = to_string(id) + ":" + s + to_string(ct++);write(fd, message.c_str(), message.size());cout << message << endl;sleep(1);}
}
void rdprc(int fd)
{int id = getpid();char buffer[512];while (1){ssize_t n = read(fd, buffer, 511);if(n>0){buffer[511] = '\0';cout << id << ' ' << n << ":" << buffer << endl;sleep(1);}}
}
int main()
{int pipefd[2];int n = pipe(pipefd);if(n!=0){cerr << "error:" << errno << "errorstring" << strerror(errno) << endl;return 1;}//0 read 1 writecout << pipefd[0] << ':' << pipefd[1] << endl;pid_t id = fork();if(id==0){close(pipefd[0]);wrprc(pipefd[1]);close(pipefd[1]);}else{close(pipefd[1]);rdprc(pipefd[0]);close(pipefd[0]);}return 0;
}

運行:

管道的5種特征:

1.匿名管道只能用來進行具有血緣關系的進程之間通信,如父子進程。

2.管道內部,自帶進程之間同步的機制(多執行流執行代碼的時候,具有明顯的順序性),父進程讀取節奏與子進程寫的節奏保持一致,緩沖區可能存在被多個進程同時訪問的情況,導致數據不一致問題(小于PPIPE_BUF字節,寫入是原子的,安全的)。

3.管道文件的生命周期是跟隨進程的生命周期。

4.管道文件在通信的時候,是面向字節流的,寫入和讀取的次數不是一一對應的(讀取會讀取一大堆)。

5.管道的通信模式,是一種特殊的半雙工模式。(不能同時兩個都寫)

管道的4種情況

1.如果管道內部是空的并且寫的fd沒有關閉,讀取條件不具備,讀進程會被阻塞。

2.如果管道被寫滿,并且fd不讀且沒被關閉,寫進程會被阻塞。

3.管道一直再被讀,但是寫被關閉了,讀端會一直讀到0,表示讀到文件結尾。

4.讀fd被關閉,OS會殺掉對應寫的進程(發送13號信號)。

進程池

提前創建一批子進程,有任務將任務交給子進程執行,當管道沒數據,子進程就在阻塞等待,父進程想哪個管道寫入,就是喚醒哪個子進程來處理任務,當然,父進程要進行后端任務的負載均衡(都忙起來)。

//task.hpp
#pragma 
#include<iostream>
using namespace std;
#include<stdlib.h>
#include<unistd.h>
void Download()
{cout << "download!" << endl;
}
void Print()
{cout << "print!" << endl;
}
void Flush()
{cout << "flush!" << endl;
}
typedef void (*task)();
#define NUM 3
task tasks[NUM];
void loadTask()
{srand(time(nullptr) ^ getpid());tasks[0] = Download;tasks[1] = Print;tasks[2] = Flush;
}
void exec(int number)
{if(number<0||number>2){return;}tasks[number]();
}
int selectTask()
{return rand() % NUM;
}
//processpool.c
#include<iostream>
#include<string>
#include<unistd.h>
using namespace std;
#include<vector>
#include"task.hpp"
#include<sys/wait.h>
class Channel
{
public:Channel(int w,pid_t i){wfd = w;id = i;}pid_t getid(){return id;}int getwfd(){return wfd;}void closewfd(){close(wfd);}private:int wfd;pid_t id;
};
void work(int rfd)
{while(1){int command = 0;int n = read(rfd, &command, sizeof(command));if (n == sizeof(int)){exec(command);}else{close(rfd);break;}}
}
void createChannel(int num,vector<Channel>* v)
{for (int i = 0; i < num; i++){int pipefd[2] = {0};int n = pipe(pipefd);if (n < 0)exit(2);pid_t id = fork();if(id==0){for(auto i:*v){i.closewfd();}close(pipefd[1]);work(pipefd[0]);exit(0);}        close(pipefd[0]);v->emplace_back(Channel(pipefd[1], id));}}
void sendTask(Channel ch,int task)
{write(ch.getwfd(),&task,sizeof(task));
}
int main(int argc,char* argv[])
{if(argc!=2){cerr << "number error!" << endl;return 1;}vector<Channel> channels;int now = 0;loadTask();int num = std::stoi(argv[1]);//1.創建子進程和通信createChannel(num, &channels);//2.通過channel發放任務int cnt = 4;while (cnt--){int task = selectTask();cout << channels[now].getid() << ' ' << task << ':' << endl;sendTask(channels[now], task);now++;now %= num;sleep(1);}// 3.回收管道和子進程for(auto &i:channels){i.closewfd();int status;int pid=0;pid = waitpid(i.getid(), &status, 0);if(pid<0)cerr << "error!" << endl;}return 0;
}

這里要注意,子進程創建會繼承父進程的文件描述符表,一定要把不需要寫端關掉。

命名管道

如果兩個進程毫無關系,那么就用命名管道進行通信。

創建命名管道:

mkfifo filename
int mkfifo(const char* filename,mode_t mode);

刪除目錄下文件:

int unlink(const char* path);

server和client進程通信(server讀,client寫):

#namePipe.hpp
#pragma 
#include<iostream>
#include<string>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<cerrno>
#include<fcntl.h>
using namespace std;
#define Size 256
const string Path = "./myfifo";
#define creater 1
#define user 2
class NamedPipe
{
public:NamedPipe(const string &Path,int id) :path(Path),id(id){if(id==creater){int ret = mkfifo(path.c_str(), 0666);if(ret!=0){perror("mkfifo");}}openNamedPipe();}int removeNamedpipe(){int ret = unlink(path.c_str());if(ret!=0){perror("mkfifo");}return ret;}~NamedPipe(){if(id==creater)removeNamedpipe();}int Read(string* out){char buffer[Size];int n = read(fd, buffer, Size);if(n>0){buffer[Size] = 0;*out = buffer;}return n;}void Write(const string& in){write(fd, in.c_str(), in.size());}private : const string path;int id;int fd;int openNamedPipe(){if(id==creater)fd = open(path.c_str(), O_RDONLY);elsefd = open(path.c_str(), O_WRONLY);return fd;}
};
#server.cpp
#include"namedPipe.hpp"
int main()
{NamedPipe pipe(Path,creater);while(1){string messages;int n=pipe.Read(&messages);if(n==0){cout << "client quit!" << endl;break;}cout << messages << endl;}return 0;
}
#client.cpp
#include"namedPipe.hpp"
int main()
{NamedPipe pipe(Path,user);while(1){cout << "in:";string messages;cin >> messages;pipe.Write(messages);}return 0;
}

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

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

相關文章

基于Spring Boot的快遞物流倉庫管理系統 商品庫存管理系統

&#x1f525;作者&#xff1a;it畢設實戰小研&#x1f525; &#x1f496;簡介&#xff1a;java、微信小程序、安卓&#xff1b;定制開發&#xff0c;遠程調試 代碼講解&#xff0c;文檔指導&#xff0c;ppt制作&#x1f496; 精彩專欄推薦訂閱&#xff1a;在下方專欄&#x1…

腳手架開發-Common封裝基礎通用工具類<基礎工具類>

書接上文 java一個腳手架搭建_redission java腳手架-CSDN博客 以微服務為基礎搭建一套腳手架開始前的介紹-CSDN博客 腳手架開發-準備配置-進行數據初始化-配置文件的準備-CSDN博客 腳手架開發-準備配置-配置文件的準備項目的一些中間件-CSDN博客 腳手架開發-Nacos集成-CSD…

軟件系統運維常見問題

系統部署常見問題 環境配置、兼容性問題。生產與測試環境的操作系統、庫版本、中間件版本不一致&#xff0c;運行環境軟件版本不匹配。新舊版本代碼/依賴不兼容。依賴缺失或沖突問題。后端包啟動失敗&#xff0c;提示類/方法/第三方依賴庫找不到或者版本沖突。配置錯誤。系統啟…

2021 IEEE【論文精讀】用GAN讓音頻隱寫術騙過AI檢測器 - 對抗深度學習的音頻信息隱藏

使用GAN生成音頻隱寫術的隱寫載體 本文為個人閱讀GAN音頻隱寫論文&#xff0c;部分內容注解&#xff0c;由于原文篇幅較長這里就不再一一粘貼&#xff0c;僅對原文部分內容做注解&#xff0c;僅供參考詳情參考原文鏈接 原文鏈接&#xff1a;https://ieeexplore.ieee.org/abstra…

PWA技術》》漸進式Web應用 Push API 和 WebSocket 、webworker 、serviceworker

PWA # 可離線 # 高性能 # 無需安裝 # 原生體驗Manifest {"name": "天氣助手", // 應用全名"short_name": "天氣", // 短名稱&#xff08;主屏幕顯示&#xff09;"start_url": "/index.html&…

數據結構——棧和隊列oj練習

225. 用隊列實現棧 - 力扣&#xff08;LeetCode&#xff09; 這一題需要我們充分理解隊列和棧的特點。 隊列&#xff1a;隊頭出數據&#xff0c;隊尾入數據。 棧&#xff1a;棧頂出數據和入數據。 我們可以用兩個隊列實現棧&#xff0c;在這過程中&#xff0c;我們總要保持其…

Java基礎 8.19

目錄 1.局部內部類的使用 總結 1.局部內部類的使用 說明&#xff1a;局部內部類是定義在外部類的局部位置&#xff0c;比如方法中&#xff0c;并且有類名可以直接訪問外部類的所有成員&#xff0c;包含私有的不能添加訪問修飾符&#xff0c;因為它的地位就是一個局部變量。局…

從父類到子類:C++ 繼承的奇妙旅程(2)

前言&#xff1a;各位代碼航海家&#xff0c;歡迎回到C繼承宇宙&#xff01;上回我們解鎖了繼承的「基礎裝備包」&#xff0c;成功馴服了public、protected和花式成員隱藏術。但——??前方高能預警&#xff1a; 繼承世界的暗流涌動遠不止于此&#xff01;今天我們將勇闖三大神…

【圖像算法 - 16】庖丁解牛:基于YOLO12與OpenCV的車輛部件級實例分割實戰(附完整代碼)

庖丁解牛&#xff1a;基于YOLO12與OpenCV的車輛部件級實例分割實戰&#xff08;附完整代碼&#xff09; 摘要&#xff1a; 告別“只見整車不見細節”&#xff01;本文將帶您深入實戰&#xff0c;利用YOLO12-seg訓練實例分割模型&#xff0c;結合OpenCV的強大圖像處理能力&…

ubuntu22.04配置遠程桌面

文章目錄前言檢查桌面類型xorg遠程桌面(xrdp)安裝xrdpxrdp添加到ssl-certwayland遠程桌面(gnome-remote-desktop)檢查安裝開啟開啟狀況檢查自動登錄奇技淫巧前言 在windows上使用遠程桌面服務&#xff0c;連接ubuntu主機的遠程桌面 檢查桌面類型 查看桌面類型、協議 echo $…

SQL Server 中子查詢、臨時表與 CTE 的選擇與對比

在 SQL Server 的實際開發過程中&#xff0c;我們常常需要將復雜的查詢邏輯分解為多個階段進行處理。實現這一目標的常見手段有 子查詢 (Subquery)、臨時表 (Temporary Table) 和 CTE (Common Table Expression)。這三者在語法、執行效率以及可維護性方面各有優勢與局限。如何選…

肖臻《區塊鏈技術與應用》第20-22講 - 以太坊難度調整、權益證明和智能合約

以太坊的“冰河時代”:詳解難度調整算法與“難度炸彈” 摘要: 為了實現遠快于比特幣的十幾秒出塊速度,以太坊必須設計一套更為靈敏和復雜的挖礦難度調整算法。本文基于北京大學肖臻老師的公開課內容,深入剖析了以太坊獨特的逐塊難度調整機制。文章首先解釋了其維持15秒平均…

C++中內存池(Memory Pool)詳解和完整示例

1. 什么是內存池&#xff1f; 內存池&#xff08;Memory Pool / Pool Allocator&#xff09; 是一種內存管理機制&#xff0c;提前向系統申請一大塊內存&#xff0c;再在這塊內存里切分、分配和回收。 它相當于在用戶空間建立了一層 “小型堆管理器”&#xff0c;避免頻繁調用系…

測試 Next.js 應用:工具與策略

1. 引言 Next.js 作為一個基于 React 的全棧框架&#xff0c;在構建復雜 Web 應用時&#xff0c;測試是確保代碼質量、功能穩定性和用戶體驗的關鍵步驟。測試可以分為單元測試、集成測試和端到端測試三種類型&#xff0c;每種類型針對不同的層面&#xff1a;單元測試驗證單個組…

IP 分片和組裝的具體過程

IP 分片和組裝的具體過程 在這里插入圖片描述 ? 16 位標識(id): 唯一的標識主機發送的報文. 如果 IP 報文在數據鏈路層被分片了, 那么每一個片里面的這個 id 都是相同的. ? 3 位標志字段: 第一位保留(保留的意思是現在不用, 但是還沒想好說不定以后要用到). 第二位置為 1 表示…

數據倉庫OLTPOLAP維度講解

?博客主頁&#xff1a; https://blog.csdn.net/m0_63815035?typeblog &#x1f497;《博客內容》&#xff1a;大數據、Java、測試開發、Python、Android、Go、Node、Android前端小程序等相關領域知識 &#x1f4e2;博客專欄&#xff1a; https://blog.csdn.net/m0_63815035/…

OpenHarmony之編譯配置白名單機制深度解析:構建系統的安全防線

一、白名單機制概述 在OpenHarmony的構建系統中&#xff0c;compile_standard_whitelist.json是一個關鍵的安全驗證機制&#xff0c;它作為編譯過程中的"守門人"&#xff0c;確保只有經過驗證的組件和依賴關系才能被納入最終構建產物。這個機制是OpenHarmony構建系統…

backward怎么計算的是torch.tensor(2.0, requires_grad=True)變量的梯度

import torch import torch.nn as nn import torch.optim as optim# 一個參數 w 2 w torch.tensor(2.0, requires_gradTrue) # 預測值 y_pred w * 3 # 6 # 真實值 y_true torch.tensor(10.0) # 損失 (預測 - 真實)^2 loss (y_pred - y_true) ** 2 # (6-10)^2 16loss.b…

戴永紅×數圖:重構零售空間價值,讓陳列創造效益!

風雨同舟&#xff0c;智贏未來。近日&#xff0c;湖南戴永紅商業連鎖有限公司&#xff08;以下簡稱“戴永紅”&#xff09;正式攜手數圖信息科技有限公司&#xff0c;全面啟動“可視化品類空間管理”項目。以數圖可視化陳列系統為引擎&#xff0c;雙方將共同推進企業零售管理的…

排查Redis數據傾斜引發的性能瓶頸

以下是針對 Redis 數據傾斜問題的完整排查與優化方案&#xff0c;結合實戰案例說明如何提升吞吐量和響應速度&#xff1a;一、問題現象定位1. ?性能監控異常?# Redis集群節點負載差異 $ redis-cli -c cluster nodes | grep master e1d7b... 10.0.0.1:637916379 master - 0 16…