【Linux系統】命名管道與共享內存

前言:????????

? ? ? ? 上文我們講到了匿名管道【Linux系統】匿名管道以及進程池的簡單實現-CSDN博客

? ? ? ? 本文我們來講一講命名管道與共享內存


命名管道

????????上面我們講到,匿名管道只能用于有血緣關系(尤其父子)的進程進行通信!但如果我們想讓沒有關系的進程進行通信,該怎么辦呢?命名管道就是答案!

? ? ? ? 進程間通信的本質是讓不同的進程看到同一份資源!命名管道也是一樣!

1.命名管道原理

? ? ? ? 1.命名管道與匿名管道一樣,本質上都是文件!

? ? ? ? 2.命名管道不同與匿名管道,命名管道是有名字、有路徑的!

? ? ? ? 3.如下圖,創建命名管道只會返回一個fd。并且當多個進程打開同一個文件時,系統并不會將其加載多次。

? ? ? ? 4.命名管道同匿名管道一樣,其緩沖區不會刷新到磁盤中!

? ? ? ? 5.如何保證多個進程打開的是同一個命名管道?路徑!路徑是唯一的!

2.命名管道的特性

命名管道的特性與匿名管道基本一樣!唯一區別就是:命名管道可用于不相關進程間的通信!

5種特性:

命名管道,可用于不相關的進程通信
命名管道文件,自帶同步機制:包含5種通信情況!
命名管道的面向字節流的
命名管道是單向通信的!(屬于半雙工的特殊情況。半雙工:任何時候一個發,一個收。全雙工:任何時候,可以同時收發)
命名管道的生命周期是由管道文件是否被刪除決定的!

5種通信情況:

只要有一方沒有打開管道文件,另一方就會阻塞在open處!直到都打開了管道文件,才會向下繼續執行!
寫慢,讀快:讀端阻塞,等待寫端
寫快,讀慢:管道緩沖區寫滿了,就要阻塞等待讀端
寫關閉,讀繼續:一直讀取,知道讀到完,返回0,表示讀取到文件末尾
寫繼續,讀關閉:無意義操作!OS會自動殺掉寫端進程(通過信號:13 SIGPIPE殺掉)

3.命名管道的接口

指令方面
//創建命名管道
mkfifo  管道名//刪除命名管道
rm  管道名
unlink  管道名
yc@hyc-alicloud:~$ mkfifo t1hyc@hyc-alicloud:~$ ls -l
total 8
prw-rw-r--  1 hyc hyc    0 Aug 22 12:01 t1hyc@hyc-alicloud:~$ unlink t1
hyc@hyc-alicloud:~$ ls -l
total 8

? ? ? ? 我們可以看到,創建的管道文件第一個字母為:p!這代表管道文件!

代碼方面

創建命名管道:

#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);pathname:FIFO 文件路徑(如 /tmp/myfifo),進程通過該路徑訪問管道。
mode:文件權限(如 0666 表示讀寫權限,需結合進程的 umask 計算實際權限)。
返回值:成功返回 0,失敗返回-1

打開命名管道:

#include <fcntl.h>
int open(const char *pathname, int flags);flags:打開模式,需指定 O_RDONLY(只讀,讀端)或 O_WRONLY(只寫,寫端)
返回值:成功返回fd,失敗返回-1

刪除命名管道:

#include <unistd.h>
int unlink(const char *pathname);FIFO文件被刪除后,已打開的進程仍可繼續使用對應資源,直到所有進程關閉文件描述符后,資源才徹底釋放

4.利用命名管道實現通信

? ? ? ? 值得一提的,命名管道的同步機制是:只要有一方沒有打開管道文件,另一方就會阻塞在open處!直到都打開了管道文件,才會向下繼續執行!

//comm.hpp#pragma once
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <iostream>
using namespace std;// 目標:實現client與service的通信#define EXIT(m)             \do                      \{                       \perror(m);          \exit(EXIT_FAILURE); \} while (0)class NameFifo
{
public:NameFifo(string path, string name): _path(path), _name(name){_fd = -1;_PATH = _path + "/" + _name;}// 創建管道void Create(){int n = mkfifo(_PATH.c_str(), 0666);if (n < 0){EXIT("mkfifo");}cout << "命名管道創建成功!\n";}// 打開管道void OpenForRead(){_fd = open(_PATH.c_str(), O_RDONLY);if (_fd < 0){EXIT("open");}cout << "讀端打開成功!\n";}void OpenForWrite(){_fd = open(_PATH.c_str(), O_WRONLY);if (_fd < 0){EXIT("open");}cout << "寫端打開成功!\n";}// 讀取數據void Read(){char buffer[1024];int n = read(_fd, buffer, sizeof(buffer) - 1);buffer[n] = 0;printf("接收到數據:%s\n", buffer);}// 寫數據void Write(){string msg;cout << "請輸入內容:\n";cin >> msg;write(_fd, msg.c_str(), msg.size());}// 關閉管道void Close(){close(_fd);unlink(_PATH.c_str());cout << "管道:" << _fd << "關閉并刪除!\n";}private:string _path;string _name;string _PATH;int _fd;
};//service.cc#include "comm.hpp"int main()
{NameFifo nf(".", "myfifo");nf.Create();nf.OpenForWrite();nf.Write();nf.Close();
}//client.cc#include "comm.hpp"int main()
{//service已經創建了管道,這里不用再創建了!NameFifo nf(".", "myfifo");nf.OpenForRead();nf.Read();nf.Close();
}


system V共享內存

system V共享內存也是進程間通信的一重要方式!

1.system V

? ? ? ? system V是Linux系統中的一種標準。它規定了系統調用接口的設計,共享內存正是滿足了這一標準。

2.共享內存的原理

? ? ? ? 如圖,顧名思義共享內存就是將相同的內存空間,通過頁表映射到不同的進程中去,達到不同進程訪問同一個數據的效果(既IPC)

????????1.想要完成上面的操作系統通過操作系統提供的系統調用來實現!

? ? ? ? 2.取消內存與進程之間的映射關系,OS會自動的釋放共享內存

? ? ? ? 3.一個操作系統必然存在多個共享內存供給多個進程使用,所以OS一定會去管理共享內存,至于如何管理,我們后面說!

3.共享內存接口

創建or獲取共享內存:

#include <sys/ipc.h>
#include <sys/shm.h>int shmget(key_t key, size_t size, int shmflg);key:共享內存的唯一標識(通過 ftok 函數生成)
size:共享內存段的大小(字節),創建新段時必須指定,獲取已有段時可設為 0shmflg:標志位(獲取)IPC_CREAT:若不存在則創建新段,若存在則打開這個共享內存,并返回(創建)IPC_EXCL:與 IPC_CREAT 配合使用(單獨使用沒有意義),若指定要創建的共享內存已經存在則返回錯誤,否則創建(想要給出權限:如0666)成功:返回共享內存段標識符(shmid,非負整數);
失敗:返回 -1,并設置 errno
#include <sys/types.h>
#include <sys/ipc.h>key_t ftok(const char *pathname, int proj_id);pathname:指向一個已存在的文件路徑的字符串,ftok 會使用該文件的 inode 編號 和 設備編號 作為生成鍵值proj_id:一個 8 位的非 0 整數用于區分同一文件對應的不同 IPC 對象,范圍為1~255成功:返回一個 key_t 類型的鍵值(非負整數)
失敗:返回 -1,并設置 errno 表示錯誤原因

讓物理內存地址與虛擬地址進行映射:

void *shmat(int shmid, const void *shmaddr, int shmflg);shmid:shmget返回的共享內存 ID
shmaddr:指定映射到進程地址空間的起始地址。通常設為NULL,由內核自動分配
shmflg:映射選項,如SHM_RDONLY(只讀映射,默認是讀寫)返回值:成功返回映射后的內存起始地址(void*),失敗返回(void*)-1(設置errno)

解除映射關系:

int shmdt(const void *shmaddr);參數:shmaddr為shmat返回的共享內存起始地址
返回值:成功返回0,失敗返回-1(設置errno)

刪除or查詢狀態:

int shmctl(int shmid, int cmd, struct shmid_ds *buf);shmid:共享內存 IDcmd:控制命令,常用:
IPC_RMID:標記共享內存段為待刪除(所有進程分離后實際刪除)
IPC_STAT:獲取共享內存屬性,存儲到buf指向的struct shmid_ds結構中
IPC_SET:修改共享內存屬性(需進程有足夠權限)
buf:指向struct shmid_ds的指針(用于IPC_STAT/IPC_SET),IPC_RMID時可設為NULL返回值:成功返回0,失敗返回-1(設置errno)

4.共享內存特性

在上面的接口中,我們會發現共享內存中存在兩個標示符:唯一標識符key、內存段標識符shmid

理解:

??key?是用戶層 “告訴內核要找哪個內存段” 的標識,shmid?是內核 “告訴用戶層如何操作這個內存段” 的句柄。兩者的交互是 “用戶層用keyshmid,再用shmid操作內存段”。簡而言之,查找時用key,操作時用shmid!!!

如何保證不同的進程訪問的是同一個內存呢?那當然是key了!只要對ftok傳入相同的函數,就可以得到相同的key,從而找到相同的內存段!
共享內存的生命周期是隨內核的!如果不顯示的刪除,那么就算進程退出了,共享內存仍然存在!
共享內存大小:必須是4KB(4096)的整數!

同步機制:

不同于管道,共享內存本身是沒有同步機制的!

共享內存屬于用戶空間,用戶可以直接訪問!

那其優點就是:速度快,映射之后可以直接看到資源,并可以直接讀取!沒有限制的

但缺點就是,沒有同步機制,這會導致數據不被保護!

比如:寫數據寫到一半,就被讀取走了!(管道調用系統調用,會被內核保護起來。而共享內存是沒有內核保護的)

5.利用共享內存實現進程間通信

//Shm.hpp#pragma once
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string>
#include <iostream>
using namespace std;// 目標:利用共享內存,實現service和client的通信#define SIZE 4096
#define gmode 0666
#define EXIT(m)             \{                       \perror(m);          \exit(EXIT_FAILURE); \}class Shm
{
public:Shm(string &pathname, int &projid){_key = ftok(pathname.c_str(), projid);}// 創建共享內存void Creat(){umask(0);_shmid = shmget(_key, SIZE, IPC_CREAT | IPC_EXCL | gmode);if (_shmid < 0){EXIT("shmget");}cout << "創建共享內存成功!\n";}// 獲取共享內存void Get(){_shmid = shmget(_key, SIZE, IPC_CREAT);if (_shmid < 0){EXIT("shmget");}cout << "獲取共享內存成功!\n";}// 映射共享內存至虛擬空間void Attach(){_start_mem = shmat(_shmid, NULL, 0);if ((long long)_start_mem < 0){EXIT("shmat");}cout << "映射成功!\n";}void Destroy(){UnAttach();int n = shmctl(_shmid, IPC_RMID, NULL);if (n < 0){EXIT("shmctl");}cout << "刪除共享內存成功!\n";}// 獲取開始地址void *Start(){return _start_mem;}private:// 解除映射void UnAttach(){int n = shmdt(_start_mem);if (n < 0){EXIT("shmdt");}cout << "解除映射成功!\n";}key_t _key;int _shmid;void *_start_mem;
};//service.cc#include "Shm.hpp"
#include <unistd.h>int main()
{string pathname = ".";int projid = 0x66;Shm shm(pathname, projid);shm.Creat();shm.Attach();// 寫入數據char *arr = (char *)shm.Start();for (int i = 'a'; i <= 'z'; i++){arr[i - 'a'] = i;sleep(1);}shm.Destroy();
}//client.cc#include "Shm.hpp"
#include <unistd.h>int main()
{string pathname = ".";int projid = 0x66;Shm shm(pathname, projid);shm.Get();shm.Attach();// 讀取數據while (1){printf("%s\n", (char *)shm.Start());sleep(1);}shm.Destroy();
}

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

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

相關文章

搜索體驗優化:ABP vNext 的查詢改寫(Query Rewrite)與同義詞治理

&#x1f50e; 搜索體驗優化&#xff1a;ABP vNext 的查詢改寫&#xff08;Query Rewrite&#xff09;與同義詞治理 &#x1f4da; 目錄&#x1f50e; 搜索體驗優化&#xff1a;ABP vNext 的查詢改寫&#xff08;Query Rewrite&#xff09;與同義詞治理1. 背景與問題界定 &…

Text2API與Text2SQL深度對比:自然語言驅動的數據交互革命

在數字化浪潮中&#xff0c;如何讓人機交互更加自然流暢&#xff1f;Text2API與Text2SQL技術應運而生&#xff0c;它們如同魔法般將自然語言轉化為機器可執行的指令&#xff0c;讓數據交互不再高不可攀。本文將深入剖析這兩項技術的原理、優劣勢及應用場景&#xff0c;帶您領略…

數據可視化與分析平臺設計與實現案例

數據可視化與分析平臺設計與實現案例(python) 下面分享一個完整的 Flask 數據可視化與分析平臺代碼,包含所有必要的組件和功能。這個平臺允許用戶上傳數據文件、進行基本的數據清洗、生成各種可視化圖表以及查看基礎統計分析結果。 產品設計 核心功能 數據上傳與管理(支…

Kotlin-基礎語法練習二

接上一篇博客 每個 Kotlin 程序都是由兩種部分組成的&#xff1a; 1、表達式&#xff08;Expressions&#xff09;&#xff1a;用于計算值的部分&#xff0c;比如 2 3、函數調用、變量賦值等&#xff0c;它們通常會返回一個結果。2、語句&#xff08;Statements&#xff09;…

與Deepseek對話了解單片機基礎知識

keil5里的c語言編程的程序燒錄到單片機里具體過程是啥&#xff1f;如何能把機器語言轉換為電路控制&#xff1f; 步驟 所在位置 核心工具 輸入->輸出 比喻 1. 編譯 Keil5 (PC) 編譯…

利用背景圖片定位套打檔案封面

某些表單設計起來比較復雜&#xff0c;或只有表單的空白圖片資料。Nhdeep檔案目錄套打工具&#xff08;nhdeep官網www.nhdeep.com&#xff09;支持將已有的表單圖片作為模版背景圖片&#xff0c;然后使用文本框進行精準的位置定位&#xff0c;再進行文本替換。 背景圖片定位套…

微信HOOK 實現自動下載視頻

1、前言 在收發消息的接口中&#xff0c;圖片和文件這類接口是相對容易自動下載&#xff0c;但是視頻的下載是需要手動點擊的&#xff0c;并且只有這一種下載方式&#xff0c;實現自動化也比較困難&#xff0c;一些項目的開發中&#xff0c;需要自動下載收到的視頻并保存&#…

【GPT入門】第57課 詳解 LLamaFactory 與 XTuner 實現大模型多卡分布式訓練的方案與實踐

【GPT入門】第57課 大模型多卡計算1. 理論2.LLamaFacotory實踐3. xtuner3.1 介紹3.1 安裝3.2 xtuner訓練3.4 訓練后格式轉換3.5 合并基礎模型與lora模型3.6 參數說明3.7 訓練過程主觀檢驗1. 理論 deepspeed的三種訓練方式 zero-1&#xff0c;優化器狀態分片。的優勢體現在多卡…

部隊多媒體信息發布系統:賦能 IPTV 與電教化,加速軍營信息化變革

在科技飛速發展的當下&#xff0c;部隊的信息化建設也在不斷推進。多媒體信息發布系統作為一種創新的技術手段&#xff0c;正逐步融入部隊的各個領域&#xff0c;為部隊的現代化建設注入強大動力。?在部隊 IPTV 方面&#xff0c;多媒體信息發布系統展現出卓越的性能。它打破了…

FTP/TCP上傳下載文件

封裝C風格地ftplib為ftp.c和ftp.h文件&#xff1a;cftplient類&#xff08;主要成員變量&#xff1a;文件大小、文件修改時間、主要成員函數&#xff1a;get函數&#xff08;遠程文件名、本地文件名、核對文件時間&#xff09;、put函數&#xff08;本地文件名、服務端文件名、…

DeepSeek V3.1深度解析:一個模型兩種思維,邁向Agent時代的第一步!

名人說&#xff1a;博觀而約取&#xff0c;厚積而薄發。——蘇軾《稼說送張琥》 創作者&#xff1a;Code_流蘇(CSDN)&#xff08;一個喜歡古詩詞和編程的Coder&#x1f60a;&#xff09; 目錄一、什么是DeepSeek V3.1&#xff1f;為什么這么火&#x1f680;1. 發布時間線回顧2.…

VsCode 便攜版(綠色版)下載及配置

下載 VsCode 便攜版&#xff0c;并確保所有配置和擴展都保存在一起&#xff0c;實現真正的“綠色版”效果 核心步驟概覽 核心原理是在 VSCode 的主程序目錄下創建一個名為 data 的文件夾&#xff0c;VSCode 啟動時如果檢測到這個文件夾&#xff0c;就會自動切換到便攜模式&am…

使用VLLM部署大模型embedding/chat 的API

模型下載&#xff1a;一般通過modelscope提供的方式進行下載&#xff0c;速度更快&#xff0c;huggingface下模型即便開啟了魔法也還是很慢&#xff0c;對于9B以上的模型都是至少15G的。 比如需要下載qwen3-embedding-8b的模型&#xff0c;可以通過提供的一段代碼自動進行下載到…

Blender模型動畫導入到UE5

UE5支持直接導入FBX文件&#xff0c;但在實際應用中筆者發現&#xff1a;剛開始使用的是UE5.3&#xff0c;在UE5.3中直接將.fbx文件拖入UE中導入后是一個個的零件&#xff0c;后來使用了datasmith插件等其他辦法&#xff0c;怎么都沒有達到想要的效果。后面升級UE5.4以后&#…

Promise詳解:Promise解決ajax回調嵌套問題

目錄 一、Promise是什么 二、回調地獄 三、Promise解決回調地獄的原理 四、promaise實例 一、Promise是什么 1、主要用于異步計算 2、可以將異步操作隊列化&#xff0c;按照期望的順序執行&#xff0c;返回符合預期的結果 4、可以在對象之間傳遞和操作promise&#xff0c…

【Kubernetes知識點】Pod調度和ConfigMaps

目錄 1.如何將特定Pod調度到指定的節點&#xff1f; 2.什么是節點的親和性&#xff1f; 3.什么是污點&#xff0c;它的主要用途是什么&#xff1f; 4.解釋ConfigMap的作用。 5.Secret和ConfigMap相比較有哪些優點。 6.解釋ResourceQuota的作用 1.如何將特定Pod調度到指定…

火車頭使用Post方法采集Ajax頁面教程

前面有寫過一篇瀑布流的采集方法&#xff0c;今天在添加一個POST方法來采集Ajax刷新頁面的教程。 之前的文章請看&#xff1a;火車頭采集動態加載Ajax數據&#xff08;無分頁瀑布流網站&#xff09; 如果遇到POST方法來架子Ajax數據&#xff0c;這和我之前寫的是兩個類型&…

【學習記錄】structuredClone,URLSearchParams,groupBy

structuredClone() 可以進行深拷貝&#xff0c;這里有詳細講解&#xff1a;Window&#xff1a;structuredClone() 方法 當需要處理包含嵌套對象或數組的復雜數據結構時&#xff0c;建議使用 structuredClone() 來保護原始數據。 舉例&#xff1a;別再用 … 擴展運算符了&#x…

30條AI編程指令

大家好&#xff0c;小機又來分享AI了。 前言&#xff1a; 凌晨三點&#xff0c;你還在像素級對齊那個永遠對不齊的按鈕&#xff1b;剛寫完的API文檔&#xff0c;產品經理一句"需求變了" 讓你瞬間崩潰&#xff1b;更扎心的是&#xff0c;實習生用AI十分鐘搞定了你要…