进程间通讯与同步技术第一篇,共享内存

进程间通讯与同步技术第一篇,共享内存

  • 共享内存
    • C++的shared_memory_object类
      • 创建共享内存段
      • 映射共享内存段
    • Linux API
      • 信号量同步

共享内存

共享内存是最快的进程间通信机制。操作系统将一个内存段映射到多个进程的地址空间中,这样多个进程就可以在该内存段中进行读写操作,而无需调用操作系统函数。但是,我们需要在读取和写入共享内存的进程之间进行某种同步。

要使用共享内存,我们必须执行两个基本步骤:

  • 向操作系统请求一个可以在进程之间共享的内存段。用户可以使用共享内存对象来创建/销毁/打开此内存:一种表示可以同时映射到多个进程的地址空间的内存的对象。
  • 将该内存的一部分或整个内存与调用进程的地址空间相关联。操作系统在调用进程的地址空间中寻找足够大的内存地址范围,并将该地址范围标记为特殊范围。该地址范围中的更改会自动被也映射了相同共享内存对象的其他进程看到。

一旦这两个步骤成功完成,进程就可以开始写入地址空间和从地址空间读取数据,以便向其他进程发送数据和从其他进程接收数据。现在,让我们看看如何使用 Boost.Interprocess 做到这一点:

C++的shared_memory_object类

创建共享内存段

正如我们提到的,我们必须使用 shared_memory_object 类来创建、打开和销毁可以由多个进程映射的共享内存段。我们可以指定该共享内存对象的访问模式(只读或读写),就像它是一个文件一样:

创建一个共享存储器段,如果它已经存在,产生一个例外using boost::interprocess;shared_memory_object shm_obj(create_only                  //only create,"shared_memory"              //name,read_write                   //read-write mode);To open or create a shared memory segment:using boost::interprocess;shared_memory_object shm_obj(open_or_create            //open or create,"shared_memory"           //name,read_only                 //read-only mode);To only open a shared memory segment. Throws if does not exist:using boost::interprocess;shared_memory_object shm_obj(open_only                    //only open,"shared_memory"              //name,read_write                   //read-write mode);

创建共享内存对象时,其大小为0。要设置共享内存的大小,用户必须使用truncate函数调用,在已打开的具有读写属性的共享内存中:

shm_obj.truncate(10000);

映射共享内存段

一旦创建或打开,进程只需要在进程的地址空间中映射共享内存对象。用户可以映射整个共享内存或其中的一部分。映射过程是使用mapped_region 类完成的。该类表示已从共享内存或其他具有映射功能的设备(例如文件)映射的内存区域。一个 mapping_region 可以从任何 memory_mappable 对象创建,正如你想象的那样,shared_memory_object 是一个 memory_mappable 对象:

using boost::interprocess;std::size_t ShmSize = 10000;//Map the second half of the memory
mapped_region region( shm                      //Memory-mappable object, read_write               //Access mode, ShmSize/2                //Offset from the beginning of shm, ShmSize-ShmSize/2        //Length of the region);//Get the address of the region
region.get_address();//Get the size of the region
region.get_size();

用户可以指定从可映射对象开始映射区域的偏移量以及映射区域的大小。如果未指定偏移量或大小,则映射整个可映射对象(在本例中为共享内存)。如果指定了偏移量,但未指定大小,则映射区域将覆盖从偏移量直到可映射对象的末尾。

Linux API

Linux 系统为共享内存提供了两个独立的 API:

  • System V API
  • POSIX API

但是,这些 API 不应混合在单个应用程序中。 POSIX 方法的一个缺点是,功能仍在开发中并且依赖于安装的内核版本,这会影响代码的可移植性。例如,POSIX API 默认将共享内存实现为内存映射文件:对于共享内存段,系统维护一个包含相应内容的后备文件。 POSIX 下的共享内存可以在没有后备文件的情况下进行配置,但这可能会影响可移植性。我的示例使用带有后备文件的 POSIX API,它结合了内存访问(速度)和文件存储(持久性)的优点。

共享内存示例有两个程序,名为 server 和 client,使用信号量同步对共享内存的访问。每当共享内存与写入器一起出现时,无论是在多处理,还是多线程中,基于内存的竞争条件的风险也会随之而来;因此,信号量用于同步对共享内存的访问。

int shm_open(const char *name, int oflag, mode_t mode);
int ftruncate(int fildes, off_t length);
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);
int shm_unlink(const char *name);

信号量同步

通用信号量也称为计数信号量,因为它具有可以递增的值。

考虑一个出租自行车的商店,有一百辆存货,供客户租用。使用计数信号量,初始化成100。

每租出一辆自行车,信号量减一;当自行车归还时,信号量加一。租赁可以持续,直到信号量为0,此时,没有更多的自行车可供租赁。一旦有自行车归还,信号量变非0,租赁可以再次进行。

二元信号量是一种特殊情况,只需要两个值:0 和 1。在这种情况下,信号量充当互斥体:互斥结构。共享内存例子使用信号量作为互斥锁。
当信号量的值为 0 时,只有server才能访问共享内存。写入后,此过程会增加信号量的值,从而允许client读取共享内存。

// ipc_1.h 
#define    BackingFile   "shared_1.txt"
#define    Sema_Server_ready    "sema_snd"
#define    Sema_Client_ready    "sema_rcv"typedef  struct personnel_s {int    id;char   name[20];int    age;
} personnel_t;#define    ByteSize    sizeof(personnel_t)
#define    AccessPerms	0664

服务器进程

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>
#include "ipc_1.h"int main(int argc, char *argv[]) {personnel_t    *pPerson;caddr_t memptr;sem_t* semptr;sem_t* sema_client_ready;int   count, i;if (argc < 2)return -1;count = atoi(argv[1]);int fd = shm_open(BackingFile,      /* name from smem.h */O_RDWR | O_CREAT,  /* read/write, create if needed */AccessPerms);     /* access permissions (0644) */if (fd < 0) {return  -1;}ftruncate(fd, ByteSize); /* get the bytes */memptr = (caddr_t)mmap(nullptr,       /* let system pick where to put segment */ByteSize,   /* how many bytes */PROT_READ | PROT_WRITE, /* access protections */MAP_SHARED, /* mapping visible to other processes */fd,         /* file descriptor */0);         /* offset: start at 1st byte */if ((caddr_t) -1  == memptr) {return -2;}fprintf(stderr, "shared mem address: %p %d:[0..%ld]\n", memptr, count, ByteSize - 1);fprintf(stderr, "backing file:       /dev/shm%s\n", BackingFile );/* semaphore code to lock the shared mem */semptr = sem_open(Sema_Server_ready, /* name */O_CREAT,       /* create the semaphore */AccessPerms,   /* protection perms */0);            /* initial value */if (semptr == (void*) -1)  {return  -3;}sema_client_ready = sem_open(Sema_Client_ready, /* name */O_CREAT,       /* create the semaphore */AccessPerms,   /* protection perms */0);            /* initial value */if (sema_client_ready == (void*) -1)  {return  -3;}pPerson = (personnel_t  *)memptr;for (i=0; i < count; i++){pPerson->id = 12345+i;if (sem_post(semptr) < 0)  {return-4;}sem_wait(sema_client_ready);printf("client picked up data\n");}pPerson->id = 0; sem_post(semptr);munmap(memptr, ByteSize); /* unmap the storage */close(fd);sem_close(semptr);shm_unlink(BackingFile); /* unlink from the backing file */return 0;
}

客户进程

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>
#include "ipc_1.h"int main(int argc, char *argv[]) {caddr_t memptr;personnel_t    *pPerson;sem_t* semptr;sem_t* sema_client_ready;int fd = shm_open(BackingFile, O_RDWR, AccessPerms);  /* empty to begin */if (fd < 0) {return -1;}printf ("Messages:%s\n", argv[1]);memptr = (caddr_t)mmap(NULL,       /* let system pick where to put segment */ByteSize,   /* how many bytes */PROT_READ | PROT_WRITE, /* access protections */MAP_SHARED, /* mapping visible to other processes */fd,         /* file descriptor */0);         /* offset: start at 1st byte */if ((caddr_t) -1 == memptr) return -2;semptr = sem_open(Sema_Server_ready, /* name */O_CREAT,       /* create the semaphore */AccessPerms,   /* protection perms */0);            /* initial value */if (semptr == (void*) -1) return -3;sema_client_ready = sem_open(Sema_Client_ready, /* name */O_CREAT,       /* create the semaphore */AccessPerms,   /* protection perms */0);            /* initial value */if (sema_client_ready == (void*) -1) return -3;do {if (!sem_wait(semptr)) { /* wait until semaphore != 0 */int i;pPerson = (personnel_t *)memptr;printf("ID:%d\n", pPerson->id);if (pPerson->id == 0)break;}sem_post(sema_client_ready);} while (1);munmap(memptr, ByteSize);close(fd);sem_close(semptr);unlink(BackingFile);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/41491.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

利用redis set 实现点赞案例 zset 对点赞进行排序

基于数据库 表 CREATE TABLE IF NOT EXISTS liked_record (id bigint NOT NULL AUTO_INCREMENT COMMENT 主键id,user_id bigint NOT NULL COMMENT 用户id,biz_id bigint NOT NULL COMMENT 点赞的业务id,biz_type VARCHAR(16) NOT NULL COMMENT 点赞的业务类型,create_time da…

海外金融机构银行保险证券数字化转型营销销售数字化成功案例讲师培训师讲授开户销售营销客户AI人工智能创新思维

金融机构需要数字营销的主要原因 数字银行、直接存款和移动网络的兴起让客户无需前往当地分行即可轻松办理银行业务。这些举措不仅提升了用户体验&#xff0c;也迫使银行向数字化世界迈进。 金融服务公司需要在数字营销渠道上保持稳固的地位&#xff0c;以免落后于大型机构。…

Stream的获取、中间方法、终结方法

1、获取Stream流 单列集合&#xff1a;foreach完整版 双列集合通过Ketset()、entryset() 数组的&#xff1a;通过Arrays Stream流的中间方法&#xff1a;链式编程&#xff0c;原stream流只能使用一次 filter&#xff1a; limit、skip&#xff1a; distinct(有自定义对象需要重写…

群体优化算法---猫群算法介绍,物流配送路径规划(包含3-opt,贪心算法)

介绍 猫群算法&#xff08;Cat Swarm Optimization&#xff0c;CSO&#xff09;是一种新型的基于群体智能的优化算法&#xff0c;由Chu et al.在2006年提出。该算法通过模拟猫的行为&#xff0c;尤其是其两种主要的行为&#xff1a;追捕行为&#xff08;seeking mode&#xff…

LangChain(三)基础问答大模型,从LLMchain开始了解chain!纯新手向

背景 经过前面两篇内容的部分&#xff0c;我想大家应该对Langchain有了一个初步的了解。那么我们接下来完善我们的基础大模型吧&#xff01;开始chain的尝试&#xff01; Chain的说明 chain可谓是Langchain的精髓所在&#xff0c;不使用chain&#xff0c;也就没必要学习Lang…

AWS云服务器的竞争优势

亚马逊网络服务&#xff08;AWS&#xff09;作为全球最大的云计算平台&#xff0c;在激烈的市场竞争中一直保持领先地位。相较于其他云服务提供商&#xff0c;AWS云服务器具有多方面的显著优势&#xff0c;使其成为众多企业和开发者的首选&#xff0c;我们结合九河云的分析一起…

机器学习 - one-hot编码技术

One-hot编码是一种数据处理技术&#xff0c;主要用于将分类变量转换为适合机器学习算法处理的格式。在One-hot编码中&#xff0c;每个类别值都会被转换成一个二进制向量&#xff0c;其中只有一个元素是1&#xff0c;其余所有元素都是0。这种编码方式确保了类别之间的独立性和唯…

如何在前端网页实现live2d的动态效果

React如何在前端网页实现live2d的动态效果 业务需求&#xff1a; 因为公司需要做机器人相关的业务&#xff0c;主要是聊天形式的内容&#xff0c;所以需要一个虚拟的卡通形象。而且为了更直观的展示用户和机器人对话的状态&#xff0c;该live2d动画的嘴型需要根据播放的内容来…

WEBHTTP

目录 理解HTTP协议请求流程 1 1 Web基础 2 Hosts文件 1 1 2网页与HTML 2 HTML概述 1 1 3静态网页与动态网页 1.2HTTP协议 1 2 1 HTTP协议概述 1 2 2 HTTP方法 HTTP支持几种不同的请求命令&#xff0c;这些命令被称为HTTP方法(HTTP method 表1一3 HTTP方法 表1&#…

开源协作wiki和文档软件Docmost

什么是 Docmost &#xff1f; Docmost 是一款开源协作 wiki 和文档软件。它是 Confluence 和 Notion 等软件的开源替代品。使用 Docmost 可以无缝创建、协作和共享知识。非常适合管理您的 wiki、知识库、文档等。目前 Docmost 处于测试阶段。 软件的主要特点 安装 在群晖上以 …

Python面试题:请解释 Python 的垃圾回收机制

Python 的垃圾回收机制主要通过引用计数&#xff08;Reference Counting&#xff09;和循环垃圾收集&#xff08;Cycle Garbage Collection&#xff09;来管理内存。以下是对这两种机制及其相关知识点的详细解析&#xff1a; 引用计数 原理 每个对象都有一个引用计数器&…

Linux运维:MySQL备份,物理冷备份,热备,完备+二进制日志

备份类型 完全备份、增量备份、差异备份 完全备份&#xff1a;整个数据集都备份 增量备份&#xff1a;仅备份最近一次完全备份或增量备份&#xff08;如果存在增量&#xff09;以来变化的数据&#xff0c;备份较快&#xff0c;还原复杂。 差异备份&#xff1a;对比前一次备…

Renesas R7FA8D1BH (Cortex®-M85) ADC模块应用

目录 概述 1 软硬件 1.1 软硬件环境信息 1.2 开发板信息 1.3 调试器信息 2 FSP和KEIL配置ADC 2.1 ADC硬件接口 2.2 FSP配置ADC 3 软件功能实现 3.1 FSP生成项目 3.2 FSP ADC模块库函数介绍 3.2.1 库函数列表 3.2.2 函数介绍 4 ADC功能代码 4.1 编写代码 4.2 代码…

计算机应用数学--第三次作业

第三次作业计算题编程题1 基于降维的机器学习2 深度学习训练方法总结 第三次作业 计算题 (15 分&#xff09;对于给定矩阵 A A A&#xff08;规模为 42&#xff09;&#xff0c;求 A A A 的 SVD&#xff08;奇异值分解&#xff09;&#xff0c;即求 U U U&#xff0c; Σ …

Ardupilot无人船(车)mavros自主控制

文章目录 前言一、启动仿真二、编写代码三、运行前言 ubuntu20.04 rover 4.4 学习资料: https://cwkj-tech.yuque.com/bsge84/suv1 https://ardupilot.org/dev/docs/mavlink-rover-commands.html http://wiki.ros.org/mavros 一、启动仿真 在ardupilot/Rover目录下执行: …

强化学习-6 DDPG、PPO、SAC算法

文章目录 1 DPG方法2 DDPG算法3 DDPG算法的优缺点4 TD3算法4.1 双Q网络4.2 延迟更新4.3 噪声正则 5 附15.1 Ornstein-Uhlenbeck (OU) 噪声5.1.1 定义5.1.2 特性5.1.3 直观理解5.1.4 数学性质5.1.5 代码示例5.1.6 总结 6 重要性采样7 PPO算法8 附28.1 重要性采样方差计算8.1.1 公…

重塑通信边界,基于ZYNQ7000 FPGA驱动的多频段多协议软件无线电平台

01、产品概述 本平台是基于高性能ZYNQ-7000系列中的XC7Z045处理器构建的多频段多协议软件无线电解决方案&#xff0c;集成了AD9364芯片——一款业界领先的1x1通道RF敏捷收发器&#xff0c;为无线通信应用提供了强大支持。其存储架构包括2路高速4GB DDR3内存、1路32GB EMMC存储以…

一道有意思的简单题 [NOIP2010 普及组] 接水问题

题目&#xff1a; 题解&#xff1a; 每一次新来的同学的接水时间都加在现在已有的水龙头中接水时间最短的&#xff0c;总时间就为n次操作后水龙头中接水时间的最长值。 #include<bits/stdc.h> using namespace std; multiset<int>s;int main(){int n,m;scanf(&qu…

uni-app组件 子组件onLoad、onReady事件无效

文章目录 导文解决方法 导文 突然发现在项目中&#xff0c;组件 子组件的onLoad、onReady事件无效 打印也出不来值 怎么处理呢&#xff1f; 解决方法 mounted() {console.log(onLoad, this.dateList);//有效// this.checkinDetails()},onReady() {console.log(onReady, this.da…

空间数据采集与管理:为什么选择ArcGISPro和Python?

你还在为找不到合适的数据而苦恼吗&#xff1f;你还在面对大量数据束手无策&#xff0c;不知如何处理吗&#xff1f;对于从事生产和科研的人员来说&#xff0c;空间数据的采集与管理是地理信息系统&#xff08;GIS&#xff09;和空间分析领域的关键环节。通过准确高效地采集和管…