進程通信方式---共享映射區(無血緣關系用的)

5.共享映射區(無血緣關系用的)

文章目錄

    • 5.共享映射區(無血緣關系用的)
      • 1.概述
      • 2.mmap&&munmap函數
      • 3.mmap注意事項
      • 4.mmap實現進程通信
        • 父子進程
          • 練習
        • 無血緣關系
      • 5.mmap匿名映射區

1.概述

  • 原理:共享映射區是將文件內容映射到進程的地址空間中,使得多個進程可以通過訪問這個共享的內存區域來實現通信。進程對映射區域的操作就如同對文件進行操作一樣,這些操作會直接反映在文件和其他共享該映射區域的進程中。

  • 示例場景:多個進程需要共同操作一個配置文件,通過將該配置文件映射到共享映射區,進程可以直接在內存中讀取和修改配置信息,而不需要頻繁地進行文件 I/O 操作。

  • 優點:結合了內存操作的高效性和文件存儲的持久性;可以方便地在不相關的進程之間實現通信,只要它們能訪問到同一個文件。

  • 缺點:對文件的操作需要注意同步問題,否則可能導致數據不一致;文件大小可能會限制共享映射區的大小。

**存儲映射I/O(Memory-mapped l/O)使一個磁盤文件與內存存儲空間中的一個緩沖區相映射。**于是當從緩沖區中取數據,就相當于讀文件中的相應字節。于此類似,將數據存入緩沖區,則相應的字節就自動寫入文件。這樣,就可在不適用read和write函數的情況下,使用地址(指針)完成I/O操作。

使用這種方法,首先應通知內核,將一個指定文件映射到存儲區域中。這個映射工作可以通過mmap函數來實
現。

2.mmap&&munmap函數

創建共享內存映射

include<sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);	

參數:

  • addr: 指定映射區的首地址。通常傳NULL,表示讓系統自動分配

  • length:共享內存映射區的大小。(<= 文件的實際大小)

  • prot: 共享內存映射區的讀寫屬性。PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE

  • flags: 標注共享內存的共享屬性,共享就是對文件的修改會寫回磁盤,私有就不會寫回磁盤。MAP_SHARED、MAP_PRIVATE

  • fd: 用于創建共享內存映射區的那個文件的 文件描述符,就是要映射到內存的文件

  • offset:默認0,表示映射文件全部。偏移位置,從哪里開始映射。需是 4k 的整數倍

返回值:

成功:映射區的首地址

失敗:MAP_FAILED (void*(-1)), errno----就是把-1強轉為void *了

釋放共享內存映射

int munmap(void *addr, size_t length);

參數

addr:mmap 的返回值,共享內存映射首地址

length:大小

返回值

成功0,失敗-1

函數使用

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>void sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc, char *argv[])
{char *p = NULL;int fd;fd = open("testmap", O_RDWR|O_CREAT|O_TRUNC, 0644);     // 創建文件用于創建映射區if (fd == -1)sys_err("open error");
/*lseek(fd, 10, SEEK_END);            // 兩個函數等價于 ftruncate()函數write(fd, "\0", 1);
*/ftruncate(fd, 20);                  // 需要借助寫權限,才能夠對文件進行拓展int len = lseek(fd, 0, SEEK_END);p = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);if (p == MAP_FAILED) {sys_err("mmap error");}// 使用 p 對文件進行讀寫操作.strcpy(p, "hello mmap");            // 寫操作printf("----%s\n", p);              // 讀操作int ret = munmap(p, len);           // 釋放映射區if (ret == -1) {sys_err("munmap error");}return 0;
}

3.mmap注意事項

思考 :

  1. 可以open的時候O_CREAT一個新文件來創建映射區嗎 ?

  2. 如果open時O_RDONLY,mmap時PROT參數指定PROT_READ|PROT_WRITE會怎樣 ?

  3. 文件描述符先關閉,對mmap映射有沒有影響 ?

  4. 如果文件偏移量為1000會怎樣 ?

  5. 對mem越界操作會怎樣?

  6. 如果mem++,munmap可否成功 ?

  7. mmap什么情況下會調用失敗 ?

    很多參數都會導致失敗

  8. 如果不檢測mmap的返回值,會怎樣?

    會死得很慘

使用注意事項:

  1. 用于創建映射區的文件大小為 0,卻指定非0大小創建映射區,出 “總線錯誤”。
  2. 用于創建映射區的文件大小為 0,也指定0大小創建映射區, 出 “無效參數”。
  3. 用于創建映射區的文件讀寫屬性為,只讀,映射區屬性為 讀、寫。 出 “無效參數”; 文件和映射區都是只讀的是可以的;文件只有寫權限,映射區只有寫權限也會報錯。(2答案)
  4. 創建映射區,需要read權限。當訪問權限指定為 “共享”MAP_SHARED是, mmap的讀寫權限應該 <=文件的open權限。 映射區只寫不行。
  5. 文件描述符fd,在mmap創建映射區完成即可關閉。后續訪問文件,用 地址訪問。(3答案)
  6. offset 必須是 4096的整數倍。(MMU 映射的最小單位 4k )(4答案)
  7. 對申請的映射區內存,不能越界訪問。 (5答案)
  8. 讀寫都沒問題,但是munmap會失敗,munmap用于釋放的 地址,必須是mmap申請返回的地址。(6答案)
  9. 映射區訪問權限為 “私有”MAP_PRIVATE, 對內存所做的所有修改,只在內存有效,不會反應到物理磁盤上。
  10. 映射區訪問權限為 “私有”MAP_PRIVATE, 只需要open文件時,文件有讀權限,用于創建映射區即可。

image-20241218222315367

mmap函數的保險調用方式:

1. fd = open("文件名", O_RDWR);
2. mmap(NULL, 有效文件大小, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

4.mmap實現進程通信

父子進程

父子等有血緣關系的進程之間也可以通過mmap建立的映射區來完成數據通信。

但相應的要在創建映射區的時候指定對應的標志位參數flags:

MAP_PRIVATE:(私有映射)父子進程各自獨占映射區;

MAP_SHARED:(共享映射) 父子進程共享映射區;

結論:

父子進程共享:1. 打開的文件 2.mmap建立的映射區(但必須要使用MAP_SHARED)

流程:

父子進程使用 mmap 進程間通信:

1.父進程 先 創建映射區。 open( O_RDWR) mmap( MAP_SHARED );

2.指定 MAP_SHARED 權限

3.fork() 創建子進程。

4.一個進程讀, 另外一個進程寫。

練習

練習:父進程創建映射區,然后fork子進程,子進程修改映射區內容,而后,父進程讀取映射區內容,查驗是
否共享

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/wait.h>int var = 100;int main(void)
{int *p;pid_t pid;int fd = open("temp", O_RDWR);//p = (int *)mmap(NULL, 40, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);p = (int *)mmap(NULL, 490, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);//p = (int *)mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); 私有的不行if(p == MAP_FAILED){		//注意:不是p == NULLperror("mmap error");exit(1);}close(fd);pid = fork();				//創建子進程if(pid == 0){*p = 7000;               // 寫共享內存var = 1000;printf("child, *p = %d, var = %d\n", *p, var);} else {sleep(1);printf("parent, *p = %d, var = %d\n", *p, var);     // 讀共享內存wait(NULL);int ret = munmap(p, 4);				//釋放映射區if (ret == -1) {perror("munmap error");exit(1);}}return 0;
}
無血緣關系

流程: 【要求會寫】

1.兩個進程 打開同一個文件,創建映射區。

2.指定flags 為 MAP_SHARED。

3.一個進程寫入,另外一個進程讀出。

【注意】:無血緣關系進程間通信。

? mmap:數據可以重復讀取。

? fifo:數據只能一次讀取。

讀端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>struct student {int id;char name[256];int age;
};void sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc, char *argv[])
{struct student stu;struct student *p;int fd; fd = open("test_map", O_RDONLY);if (fd == -1)sys_err("open error");p = mmap(NULL, sizeof(stu), PROT_READ, MAP_SHARED, fd, 0);if (p == MAP_FAILED)sys_err("mmap error");close(fd);while (1) {printf("id= %d, name=%s, age=%d\n", p->id, p->name, p->age);usleep(10000);}munmap(p, sizeof(stu));return 0;
}

寫端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>struct student {int id;char name[256];int age;
};void sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc, char *argv[])
{struct student stu = {1, "xiaoming", 18};struct student *p;int fd; //    fd = open("test_map", O_RDWR|O_CREAT|O_TRUNC, 0664);fd = open("test_map", O_RDWR);if (fd == -1)sys_err("open error");ftruncate(fd, sizeof(stu));p = mmap(NULL, sizeof(stu), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);if (p == MAP_FAILED)sys_err("mmap error");close(fd);while (1) {memcpy(p, &stu, sizeof(stu));stu.id++;sleep(2);}munmap(p, sizeof(stu));return 0;
}

5.mmap匿名映射區

匿名映射:只能用于 血緣關系(父子)進程間通信。

p = (int *)mmap(NULL, 40, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);

映射區大小想要多少寫多少

權限想要啥寫啥

文件描述符的地方傳-1

flags要 | 下面提到的兩個宏

image-20241218224059685

/dev/zero 從這個文件里面拿數據可以隨便拿,想要多大拿多大的數據,只不過讀出來都是文件空洞

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

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

相關文章

《云原生安全攻防》-- K8s安全框架:認證、鑒權與準入控制

從本節課程開始&#xff0c;我們將來介紹K8s安全框架&#xff0c;這是保障K8s集群安全比較關鍵的安全機制。接下來&#xff0c;讓我們一起來探索K8s安全框架的運行機制。 在這個課程中&#xff0c;我們將學習以下內容&#xff1a; K8s安全框架&#xff1a;由認證、鑒權和準入控…

day08-別名-重定向-去重排序等

1.重復用touch命令創建同一份文件&#xff0c;會修改文件的時間戳。 alias命令&#xff1a; 別名 查看已有別名&#xff1a;alias [rootoldboy ~]# alias alias cpcp -i alias egrepegrep --colorauto alias fgrepfgrep --colorauto alias grepgrep --colorauto alias l.ls…

Qt WORD/PDF(四)使用 QAxObject 對 Word 替換(QWidget)

關于QT Widget 其它文章請點擊這里: QT Widget 國際站點 GitHub: https://github.com/chenchuhan 國內站點 Gitee : https://gitee.com/chuck_chee 姊妹篇: Qt WORD/PDF&#xff08;一&#xff09;使用 QtPdfium庫實現 PDF 操作 Qt WORD/PDF&#xff08;二…

設計一個基礎JWT的多開發語言分布式電商系統

在設計一個分布式電商系統時&#xff0c;保證系統的可擴展性、性能以及跨語言的兼容性是至關重要的。隨著微服務架構的流行&#xff0c;越來越多的電商系統需要在多個服務間共享信息&#xff0c;并且保證服務的安全性。在這樣的場景下&#xff0c;JSON Web Token&#xff08;JW…

實踐分享 | 公共數據金融應用的理論探索與實踐研究—以人民幣銀行結算賬戶數據應用為例

摘要:公共數據具有高權威性、高準確性、高價值性以及高應用性的特點,實現公共數據的金融應用對更好服務實體經濟、防控金融風險和提升金融服務水平具有重要現實意義。本文從理論探索與實踐研究兩個層面分析了公共數據金融應用的具體問題,一方面探索性的給出了公共數據金融應…

Node的學習以及學習通過Node書寫接口并簡單操作數據庫

Node的學習 Node的基礎上述是關于Node的一些基礎&#xff0c;總結的還行&#xff1b; 利用Node書寫接口并操作數據庫 1. 初始化項目 創建新的項目文件夾&#xff0c;并初始化 package.json mkdir my-backend cd my-backend npm init -y2. 安裝必要的依賴 安裝Express.js&…

計算機視覺中的特征提取算法

摘要&#xff1a; 本文聚焦于計算機視覺中的特征提取算法&#xff0c;深入探討尺度不變特征變換&#xff08;SIFT&#xff09;算法。詳細闡述 SIFT 算法的原理&#xff0c;包括尺度空間構建、關鍵點檢測、方向分配與特征描述子生成等核心步驟。通過 C#、Python 和 C 三種編程語…

MySQL 主從復制與 Binlog 深度解析

目錄 1. Binlog的工作原理與配置2. 主從復制的設置與故障排除3. 數據一致性與同步延遲的處理 小結 MySQL的binlog&#xff08;二進制日志&#xff09;和主從復制是實現數據備份、容災、負載均衡以及數據同步的重要機制。在高可用性架構和分布式數據庫設計中&#xff0c;binlog同…

排隊論、負載均衡和任務調度關系

目錄 排隊論、負載均衡和任務調度關系 一、排隊論 二、負載均衡 三、任務調度 四、總結 排隊論、負載均衡和任務調度關系 排隊論為負載均衡和任務調度提供了數學理論和方法支持 排隊論、負載均衡和任務調度是三個相關但不同的概念。以下是對這三個概念的詳細解釋和它們之…

java版詢價采購系統 招投標詢價競標投標系統 招投標公告系統源碼

功能描述 1、門戶管理&#xff1a;所有用戶可在門戶頁面查看所有的公告信息及相關的通知信息。主要板塊包含&#xff1a;招標公告、非招標公告、系統通知、政策法規。 2、立項管理&#xff1a;企業用戶可對需要采購的項目進行立項申請&#xff0c;并提交審批&#xff0c;查看所…

景聯文科技入選中國信通院發布的“人工智能數據標注產業圖譜”

近日&#xff0c;由中國信息通信研究院、中國人工智能產業發展聯盟牽頭&#xff0c;聯合中國電信集團、沈陽市數據局、保定高新區等70多家單位編制完成并發布《人工智能數據標注產業圖譜》。景聯文科技作為人工智能產業關鍵環節的代表企業&#xff0c;入選圖譜中技術服務板塊。…

【小沐學GIS】基于C++繪制三維數字地球Earth(OpenGL、glfw、glut、QT)第三期

&#x1f37a;三維數字地球系列相關文章如下&#x1f37a;&#xff1a;1【小沐學GIS】基于C繪制三維數字地球Earth&#xff08;456:OpenGL、glfw、glut&#xff09;第一期2【小沐學GIS】基于C繪制三維數字地球Earth&#xff08;456:OpenGL、glfw、glut&#xff09;第二期3【小沐…

實景視頻與模型疊加融合?

[視頻GIS系列]無人機視頻與與實景模型進行實時融合_無人機視頻融合-CSDN博客文章瀏覽閱讀1.5k次&#xff0c;點贊28次&#xff0c;收藏14次。將無人機視頻與實景模型進行實時融合是一個涉及多個技術領域的復雜過程&#xff0c;主要包括無人機視頻采集、實景模型構建、視頻與模型…

MySQL通過binlog日志進行數據恢復

記錄一次阿里云MySQL通過binlog日志進行數據回滾 問題描述由于阿里云遠程mysql沒有做安全策略 所以服務器被別人遠程攻擊把數據庫給刪除&#xff0c;通過查看binlog日志可以看到進行了drop操作&#xff0c;下面將演示通過binlog日志進行數據回滾操作。 1、查詢是否開始binlog …

IDEA 修改格式化僅格式化本次改動代碼

最近總是發現格式化的時候會格式化文件所有代碼&#xff0c;提交Git 后再看提交日志&#xff0c;就很不清晰。修改方式如下 中文&#xff1a; 格式化代碼快捷鍵[中文配置]&#xff1a; 英文&#xff1a; 格式化代碼快捷鍵[英文配置]&#xff1a;

el-table ToggleRowSelection實現取消選中沒效果(virtual-scroll)

場景&#xff1a; 就是在虛擬列表el-table選中之后 點擊查詢 默認之前選中的 現象&#xff1a; 就是實現選中&#xff0c; 但是無法去除勾選等等 問題發現&#xff1a; 看定位的數據 有多個一樣的&#xff0c;我想著勾選之前 先去掉勾選 &#xff0c;但是沒效果或者說“相同的…

【含開題報告+文檔+PPT+源碼】基于微信小程序的點餐系統的設計與實現

開題報告 隨著互聯網技術的日益成熟和消費者生活水平與需求層次的顯著提升&#xff0c;外賣點餐平臺在中國市場上迅速興起并深深植根于民眾日常生活的各個角落。這類平臺的核心在于構建了一個基于互聯網的強大訂餐服務系統&#xff0c;它無縫整合了餐飲商戶資源與廣大消費者的…

解決 MyBatis 中空字符串與數字比較引發的條件判斷錯誤

問題復現 假設你在 MyBatis 的 XML 配置中使用了如下代碼&#xff1a; <if test"isCollect ! null"><choose><when test"isCollect 1">AND exists(select 1 from file_table imgfile2 where task.IMAGE_SEQimgfile2.IMAGE_SEQ and im…

SpringBoot 手動實現動態切換數據源 DynamicSource (中)

大家好&#xff0c;我是此林。 SpringBoot 手動實現動態切換數據源 DynamicSource &#xff08;上&#xff09;-CSDN博客 在上一篇博客中&#xff0c;我帶大家手動實現了一個簡易版的數據源切換實現&#xff0c;方便大家理解數據源切換的原理。今天我們來介紹一個開源的數據源…

ASCII碼簡介以及在php中的使用

什么是 ASCII&#xff1f; ASCII&#xff08;American Standard Code for Information Interchange&#xff0c;美國信息交換標準代碼&#xff09;是一種字符編碼標準&#xff0c;用于在計算機、通信設備及其他設備中表示文字、符號和控制信息。它最早于 1963 年由美國國家標準…