Linux_共享內存通信

目錄

1、共享內存原理

2、申請共享內存

2.1 ftok?

2.2 測試shmget、ftok?

2.3 查看系統下的共享內存?

3、關聯共享內存

3.1 測試shmat

4、釋放共享內存?

4.1 測試shmctl?

5、實現共享內存通信?

6、共享內存的特性

結語?


前言:

????????在Linux下,有一種進程間通信方式(IPC)名為共享內存,他是IPC中通信最快的方式(通信方式為全雙工),因為他直接在物理內存上創建一塊區域并且映射在進程的地址空間中,使得進程使用共享內存就如同直接使用動態申請的空間,因此通信過程少了內核的系統調用步驟,以至于相比于其他IPC模式速度更快,不過也正是因為在通信時不受內核管轄,導致共享內存不具備同步互斥機制,因此需要用戶手動處理同步互斥問題。

????????但是需要注意的是共享內存雖然使用起來如同動態空間,但是他的底層和動態空間不一樣,動態空間具有獨立性,只限于單個進程內部的訪問,而共享內存允許多個無親緣進程進行通信,因此他和動態空間是有區別的。

1、共享內存原理

? ? ? ? 共享內存的目的就是為了進程間通信,而進程間通信的核心觀念是讓不同的進程看到同一份資源,所以共享內存必須在物理內存上開辟一塊空間,并且映射到進程地址空間中的共享區,具體示意圖如下:

? ? ? ? 但是共享內存的申請和malloc申請是不一樣的,因為共享內存要面向所有進程,要做到這一點就必須調用系統接口,所以要進行共享內存通信必須調用系統接口。

2、申請共享內存

? ? ? ? 在物理內存上申請共享內存的接口是shmget,該接口介紹如下:

#include <sys/ipc.h>
#include <sys/shm.h>int shmget(key_t key, size_t size, int shmflg);
//key是用戶給這段共享內存設置的名字,一個key對應一個共享內存
//size表示申請共享內存的大小
//shmflg表示權限設置,常用的有IPC_CREAT和IPC_EXCL//調用成功返回非負整數表示共享內存的標識碼(給系統看的),失敗返回-1

????????著重介紹shmflg:

? ? ? ? 1、當傳遞的是IPC_CREAT|IPC_EXCL,表示若以當前key值申請的共享內存不存在,則創建一個并返回新共享內存的標識碼。若以當前key值申請的共享內存存在則返回-1,表示申請失敗。

? ? ? ? 2、當傳遞的是IPC_CREAT,表示若以當前key值申請的共享內存不存在,則創建一個并返回新共享內存的標識碼。若以當前key值申請的共享內存存在則返回該共享內存的標識碼。

? ? ? ? 所以使用IPC_CREAT|IPC_EXCL可以判斷一個key對應的共享內存是否存在,即key值是否被用過,當我們想用一段新的共享內存則可以使用IPC_CREAT|IPC_EXCL。

? ? ? ? key值的作用是判斷兩個進程的共享內存是否為同一個,兩個進程所用的key一樣說明他們共用同一個共享內存,反之則否,因此可以理解為key值是用戶給一段共享內存起的名字,而shmget返回值是系統給這段共享內存起的名字。

2.1 ftok?

? ? ? ? shmget需要用到key值,key的類型雖然是key_t,但是也可以傳一個int類型的值給到key,只不過這么做會導致潛在的重名風險,并且key的值需要程序員自己維護,于是系統提供了一個接口ftok,他像是一個算法,可以計算并返回一個key_t類型的值,該接口介紹如下:

#include <sys/types.h>
#include <sys/ipc.h>key_t ftok(const char *pathname, int proj_id);
//接收一個路徑和一個整形
//成功返回一個key_t類型的值,失敗返回-1

? ? ? ? ?所以兩個進程調用ftok時傳參是一樣的,那么這兩個進程就會獲得相同的key值,這樣兩個進程就能看到同一份資源了,也就完成了通信的前提。

2.2 測試shmget、ftok?

?????????先用代碼測試上述接口,測試代碼如下:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <iostream>using namespace std;int main()
{const char *pathname = "/home/zh";int proj_id = 12;int size = 4096;key_t key = ftok(pathname, proj_id);if (key < 0){perror("ftok");return -1;}cout << "key值被成功創建,key:" << key << endl;int shmid = shmget(key, size, IPC_CREAT | IPC_EXCL);if (shmid < 0){perror("shmget");return -1;}cout<<"共享內存標識碼被成功創建,shmid:"<<shmid<<endl;return 0;
}

? ? ? ? 運行結果:

2.3 查看系統下的共享內存?

? ? ? ? 共享內存不同于動態申請空間,動態空間的生命周期隨進程。但是對于共享內存而言,若用戶不主動釋放共享內存,則共享內存會一直存活在系統中,他的生命周期隨內核,即內核重啟才會清理這些共享內存,在Linux下用指令ipcs -m查看當下系統的共享內存,測試如下:

? ? ? ? 并且可以通過指令ipcrm -m shmid刪除對應的shmid,測試如下:

3、關聯共享內存

? ? ? ? ?上述接口shmget可以申請一塊共享內存,但是申請到了不意味著就可以直接使用共享內存進行通信,要進行通信還要關聯共享內存,關聯共享內存的接口介紹如下:

#include <sys/types.h>
#include <sys/shm.h>//關聯共享內存
void *shmat(int shmid, const void *shmaddr, int shmflg);
//shmid表示要關聯的共享內存標識碼
//shmaddr若不為NULL且shmflg不為SHM_RND,表示將共享內存的地址附加到shmaddr處
//shmaddr若為NULL,則該函數的返回值作為共享內存的地址(通常都設為NULL)
//shmflg表示權限設置,通常設為0表示對共享內存可讀可寫
//調用成功返回指向共享內存的指針,失敗返回值(void*)-1//去關聯
int shmdt(const void *shmaddr);
//讓調用該函數的進程不再關聯該共享內存
//shmaddr表示共享內存的地址

? ? ? ? 總的來說,調用shmat關聯共享內存后,會拿到一個執行該共享內存的指針,通過該指針就可以對共享內存進行讀寫操作。

3.1 測試shmat

? ? ? ? 因為申請共享內存的代碼后續會被重復使用,為了后續更好的測試,所以對申請共享內存的接口進行再一層封裝,封裝成sharemem.hpp文件,代碼如下:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <iostream>
#include <unistd.h>using namespace std;const char *pathname = "/home/zh";
int proj_id = 12;
int size = 4096;key_t getkey()//封裝ftok
{key_t key = ftok(pathname, proj_id);if (key < 0){perror("ftok");exit(-1);}cout << "key值被成功創建,key:" << key << endl;return key;
}int getshm(int shmflg)//封裝shmget
{key_t key = getkey();int shmid = shmget(key, size, shmflg);if (shmid < 0){perror("shmget");exit(-1);}cout << "共享內存標識碼被成功創建,shmid:" << shmid << endl;return shmid;
}int creatnewshm()//只想用最新的共享內存來進程通信
{return getshm(IPC_CREAT|IPC_EXCL|0666);//為了能夠觀察到變化,所以要保證共享內存的權限
}int getoldshm()//獲取一個已經存在的共享內存進行通信
{return getshm(IPC_CREAT);
}

?????????后續的測試只需要包含該文件即可,測試shmat代碼如下:

#include "sharemem.hpp"int main()
{int shmid = creatnewshm();cout<<"申請共享內存成功"<<endl;sleep(2);//觀察nattch的值char* poi = (char*)shmat(shmid,NULL,0);cout<<"關聯共享內存成功"<<endl;sleep(2);//觀察nattch的值return 0;
}

? ? ? ? 運行結果:

? ? ? ? 其中,右側nattch表示當前有多少個進程在關聯該共享內存,當一個進程關聯某個共享內存后,該共享內存的nattch+1,并且當該進程結束后,對應的nattch會-1。當然也可以使用shmdt手動去關聯。

4、釋放共享內存?

? ? ? ? 手動釋放共享內存的接口是shmctl,該接口本質的功能是控制共享內存,只不過也有刪除選項,具體介紹如下:

#include <sys/ipc.h>
#include <sys/shm.h>int shmctl(int shmid, int cmd, struct shmid_ds *buf);
//shmid表示要釋放的共享內存的標識碼
//cmd表示該函數執行的具體任務,比如IPC_RMID表示刪除任務
//buf表示指向共享內存數據結構的指針,若使用刪除任務則該指針置為NULL即可//調用成功返回0,失敗返回-1

4.1 測試shmctl?

? ? ? ? ?測試shmctl的代碼如下:

#include "sharemem.hpp"int main()
{int shmid = creatnewshm();cout<<"申請共享內存成功"<<endl;sleep(2);//觀察nattch的值char* poi = (char*)shmat(shmid,NULL,0);cout<<"關聯共享內存成功"<<endl;sleep(2);//觀察nattch的值shmdt(poi);cout<<"成功去關聯共享內存"<<endl;sleep(2);//觀察nattch的值shmctl(shmid,IPC_RMID,nullptr);cout<<"成功刪除共享內存"<<endl;return 0;
}

? ? ? ? 運行結果:

? ? ? ? 從結果可以看到,無論是去關聯測試還是刪除共享內存,在右邊的監控中都會顯示對應的效果。?

5、實現共享內存通信?

?????????有了上述的接口以及sharemem.hpp文件,就可以實現兩個進程的通信了,所以需要寫一個客戶端進程和一個服務器進程,其中服務器進程創建共享內存,讓他們兩都關聯該共享內存,并且由客戶端向服務器發送消息,服務器代碼如下:

#include "sharemem.hpp"int main()
{int shmid = creatnewshm();char *poi = (char *)shmat(shmid, nullptr, 0);cout << "關聯共享內存成功" << endl;while (true){cout<<"服務器接收:"<<poi<<endl;sleep(1);}shmdt(poi);shmctl(shmid,IPC_RMID,nullptr);return 0;
}

? ? ? ? 客戶端代碼如下:

#include "sharemem.hpp"int main()
{int shmid = getoldshm();char* poi = (char*)shmat(shmid,nullptr,0);cout<<"關聯共享內存成功"<<endl;while (true){string message;cout<<"客戶端發送:";cin>>message;strcpy(poi,message.c_str());}shmdt(poi);return 0;
}

? ? ? ? 測試結果:

? ? ? ? 從結果可以發現,共享內存的通信本質就是對一個空間進行內存式的訪問,無需調用read、write這些系統接口,直接用內存函數寫入數據至內存對方就能夠讀取到內存里的數據。

6、共享內存的特性

? ? ? ? 1、共享內存不需要調用系統接口實現進程間通信,只需要調用內存函數對內存進行讀寫即可實現進程間通信。

? ? ? ? 2、共享內存本身沒有同步互斥的概念,體現在上面的運行結果中讀端會一直讀內容(說明沒有同步),并不會因為寫端還未寫而阻塞住。并且讀端和寫端可以同時訪問共享內存(說明沒有互斥)。

? ? ? ? 3、共享內存在讀寫效率上更為高效,因為少了write和read這些步驟,即少了一層拷貝。?

結語?

? ? ? ? 以上就是關于共享內存通信的講解,共享內存作為IPC的其中一種方式,相對于其他通信方式,他有利有弊,在實際應用里先熟悉他的接口以及使用共享內存的步驟:申請共享內存(包括創建key值)、關聯共享內存(shmat)、去關聯(shmdt)、釋放共享內存(shmctl)?,通過以上步驟可以實現完整的共享內存通信。

????????最后如果本文有遺漏或者有誤的地方歡迎大家在評論區補充,謝謝大家!!

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

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

相關文章

爆!Java高級特性之Stream API詳解

爆&#xff01;Java高級特性之Stream API詳解 Java 8引入的Stream API可以說是一個革命性的特性,讓我們告別了又臭又長的for循環,迎來了函數式編程的春天。今天就讓我們來一起深入了解這個讓人又愛又恨的Stream API吧! 什么是Stream? Stream就像一個高級的迭代器,允許我們以…

分支與循環

目錄 1. if語句 1&#xff09;if 2) else 3&#xff09;分支中包含多條語句 4&#xff09;if嵌套 2.關系操作符 3.條件操作符 4.邏輯操作符&#xff1a;&& || ! 1) 邏輯取反運算符 !?編輯 2 與運算符?編輯 3) 或運算符?編輯 4) 閏年的判斷 5) 短路 …

LangChain 概述 (模塊索引)

文章目錄 一、下載二、核心功能1、流式傳輸 streaming 三、LCEL四、組成部分1、Promp template2、Example selectors (示例選擇器)3、Chat models (聊天模型)4、Messages (消息)5、LLMs (大語言模型) 一、下載 二、核心功能 其中包括以下內容&#xff1a; 從模型中返回結構化的…

若依 Vue 前端分離 3.8.8 版中生成的前端代碼中關于下拉框只有下拉箭頭的問題

生成代碼修改前 <el-form-item label"課程學科" prop"subject"><el-select v-model"queryParams.subject" placeholder"請選擇課程學科" clearable><el-optionv-for"dict in course_subject":key"dict…

Mysql中常用函數的使用示例

場景 基礎知識回顧&#xff1a;mysql中常用函數的使用示例。 注&#xff1a; 博客&#xff1a;霸道流氓氣質-CSDN博客 實現 數學函數 -- ABS(x)返回x的絕對值 SELECT ABS(-1),ABS(2); -- PI()返回圓周率 SELECT PI(); -- SQRT(x)返回非負數x的二次方根 SELECT SQRT(4); -…

【博士每天一篇文獻-算法】Adult neurogenesis acts as a neural regularizer

閱讀時間&#xff1a;2023-12-20 1 介紹 年份&#xff1a;2022 作者&#xff1a;Lina M. Tran&#xff0c;Adam Santoro&#xff0c;谷歌DeepMind 期刊&#xff1a; Proceedings of the National Academy of Sciences 引用量&#xff1a;13 代碼&#xff1a;https://github.c…

A4-C四驅高防輪式巡檢機器人

在當今數字化和智能化迅速發展的時代&#xff0c;旗晟智能帶來了一款革命性的創新產品——A4-C四驅高防輪式巡檢機器人。這款機器人以其卓越的性能和多功能性&#xff0c;為工業巡檢領域帶來了全新的解決方案。 一、產品亮點 1、四驅動力與高防護設計 四驅高防輪式巡檢機器人…

ASUS/華碩槍神4 G532L G732L系列 原廠win10系統 工廠文件 帶F12 ASUS Recovery恢復

華碩工廠文件恢復系統 &#xff0c;安裝結束后帶隱藏分區&#xff0c;一鍵恢復&#xff0c;以及機器所有驅動軟件。 系統版本&#xff1a;Windows10 原廠系統下載網址&#xff1a;http://www.bioxt.cn 需準備一個20G以上u盤進行恢復 請注意&#xff1a;僅支持以上型號專用…

GPT-2怎么做翻譯任務?

首先需要知道的是GPT-2無論在訓練還是推理過程都是只使用了transformer decoder&#xff0c;并沒有使用encoder結構&#xff0c;那么它是怎么做的翻譯任務呢&#xff1f; 使用transformer encoderdecoder的著名架構有&#xff1a; 最原始的transformer model&#xff08;Atte…

計算機應用數學--第一次作業

第一次作業計算題編程題 &#xff08;20分&#xff09; 第一次作業 計算題 &#xff08;20分&#xff09;求 E ( X ) E(X) E(X)&#xff0c; V a r ( X ) Var(X) Var(X) &#xff08;1&#xff09; X X X 服從 [ a , b ] [a,b] [a,b] 均勻分布。 &#xff08;2&#xff09;…

操作系統期末必考概念大綱(整理·全)

第一章 1、 操作系統的概念 2、 計算機發展的四個階段 3、 手工操作階段、批處理系統階段、多道程序系統階段、分時操作系統階段、通用操作系統階段 4、 批處理系統&#xff08;聯機、脫機&#xff09; 5、 操作系統的6個基本類型 6、 多道批處理特征 7、 分時系統特點 8、 算法…

第二節-K8s詞匯表

關鍵字詞匯表 https://kubernetes.io/zh-cn/docs/reference/glossary/?fundamentaltrue API Group (API 組)Kubernetes API 中的一組相關路徑。 API 服務器亦稱作:kube-apiserver API 服務器是 Kubernetes 控制平面的組件&#xff0c; 該組件負責公開了 Kubernetes API&…

2024年智慧教育與社會科學國際會議 (ICSSS 2024)

2024年智慧教育與社會科學國際會議 (ICSSS 2024) 2024 International Conference on Smart Education and Social Sciences 【重要信息】 大會地點&#xff1a;北京 大會官網&#xff1a;http://www.icicsss.com 投稿郵箱&#xff1a;icicssssub-conf.com 【注意&#xff1a;稿…

Stable-diffusion-WebUI 的API調用(內含文生圖和圖生圖實例)

前情提要 在之前嘗試使用Diffusers庫來進行stable-diffusion的接口調用以及各種插件功能實現&#xff0c;但發現diffusers庫中各復雜功能的添加較為麻煩&#xff0c;而且難以實現對采樣器的添加&#xff0c;safetensors格式模型的讀取。在官網上找到了webui有專門的api接口&am…

1117 數字之王

solution 判斷現有數字是否全為個位數 全為個位數&#xff0c;找出出現次數最多的數字&#xff0c;并首行輸出最多出現次數&#xff0c;第二行輸出所有出現該次數的數值不全為個位數 若當前位數值為0&#xff0c;無需處理若當前位數值非0&#xff0c;則每位立方相乘&#xff0…

10.x86游戲實戰-匯編指令lea

免責聲明&#xff1a;內容僅供學習參考&#xff0c;請合法利用知識&#xff0c;禁止進行違法犯罪活動&#xff01; 本次游戲沒法給 內容參考于&#xff1a;微塵網絡安全 工具下載&#xff1a; 鏈接&#xff1a;https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd6tw3 提…

Prometheus + Grafana 監控系統搭建使用指南-redis_exporter 安裝與配置

Redis 接入 Prometheus 監控系統 系列文章目錄 Prometheus 的安裝部署Grafana的安裝部署Linux服務器接入Prometheus監控-Node Exporter 安裝指南Prometheus 接入SpringBoot微服務監控Mysql 接入 Prometheus RocketMQ 接入Prometheus 監控ElasticSearch 接入 PrometheusNacos …

vue使用axios獲取信息的案例

List組件&#xff08;用來展示搜索的信息&#xff09; <template><div class"row"><!-- 列表數據 --><div class"card" v-for"user in info.users" :key"user.login" v-show"info.users.length">&l…

智慧校園-資產管理系統總體概述

智慧校園資產管理系統是面向教育機構設計的一體化數字平臺&#xff0c;其核心目標在于通過先進的信息技術手段&#xff0c;全面優化校園內部的資產管理流程。該系統致力于提升資產管理的效率與透明度&#xff0c;同時降低成本并確保所有操作符合財務及審計規范&#xff0c;為校…

Debezium系列之:單表多個tinyint(1)類型字段支持選擇字段轉化為int或者boolean

Debezium系列之:單表多個tinyint 1類型字段支持選擇字段轉化為int或者boolean 一、需求二、相關技術三、創建表和插入數據四、參數設置和字段選擇五、查看數據一、需求 單表中有多個tinyint(1)字段,需要能支持選擇某個字段類型轉化為int,某個字段類型轉化為boolean二、相關技…