进程间通信(共享内存)

目录

前置:

一 原理

二 API

1. shmgetr

2. shmctl

3. 指令操作

2. 删除

3. 挂接

4. 断开挂接

三 demo代码

四 共享内存的特征


前置:

1.前面说的不管是匿名管道还是命名管道都是基于文件的思想构建的一套进程间通信的方案,那有没有完全从0单独设计一套呢?

2. 共享内存作为 system v 标准,是由操作系统自主从0搭建的一套进程间通信机制,相对于管道而言也更快,那么下面来看看具体是怎么实现的。

一 原理

1. 进程之间通信之前必须要看到同一份资源,比如管道,看到同一个管道文件(路径),子进程继承父进程文件描述符。

2. 共享内存其实是在内存中开辟一段空间,并把起始地址映射到虚拟地址空间的共享区当中,访问这个虚拟地址也就访问到内存上的空间了,那么2个毫不相干的进程怎么看到这个共享内存呢?

3. 之前说的动态库,在程序运行期间在内存中寻找库文件,找不到在去磁盘上加载,所以在内存中有很多的动态库,势必也要管理维护起来并且提供一个字段来标识这个实例,共享内存也同样如此,在内存中也有个结构进行维护并标识起来。

4. 让不同进程看到同一份标识,系统提供了一个API

#include <sys/types.h>
#include <sys/ipc.h>key_t ftok(const char *pathname,  // 随便传入路径int proj_id            // 随便传入一个id// key_t -> int);

1. 传入一个路径和id并通过算法形成一个key_t结构,本质是int类型,算法是固定的,所以不同的进程传入相同的字符串和id得到的key_t都是一样的,这是用户传入数据生成的。

2. 返回值为-1错误,其他均正确。

所以不同的进程传入相同的路径和id就能看到同一个共享内存了。

5. 建立共享内存的映射,然后就需要进行把进程和共享内存进行挂接,也就是绑在一起,进行后续通信,结束在断开挂接。

6. 共享内存只有创建和挂接/断开挂接/释放共享内存的时候使用了系统调用,通信的时候不需要,所以直接在用户层直接向物理内存写入数据,是进程间通信里最快的,仅需一次拷贝物理内存里的数据。

二 API

1. shmgetr
#include <sys/ipc.h>
#include <sys/shm.h>int shmget(key_t key,    // 用户生成的 key 值 size_t size,  // 共享内存的大小int shmflg    // 选项: 创建/获取....);// 返回值: 内核维护的 shmid 值,用来管理共享内存的结构
2. shmctl
#include <sys/ipc.h>
#include <sys/shm.h>int shmctl(int shmid,            // shmget的返回值int cmd,              // 对共享内存: 删除/修改等操作struct shmid_ds *buf  // 共享内存的结构里的字段);
// 返回值: 成功为0,失败-1

为什么有了 key ,还要有 shmid ?key是用户形成的只是用来获取和创建共享内存的,并不能对已经存在的共享内存进行字段修改/结构修改等,只有shmid能操作,本质就是 shmid 属于内核提供的,key是有用户提供的,他们的功能侧重点不同,用户管用户,内核管内核,变相的解耦。 

3. 指令操作

1. 查看

ipcs -m // 共享内存相关信息
ipcs -q // 消息队列相关信息
ipcs -s // 信号量相关信息

查询到的字段

key:    用户形成的随机值,用来获取,创建访问共享内存。

shmid:shmget的返回值,用来管理共享内存结构的。

owner:谁创建的。

perms:权限是什么。

bytes: 共享内存多大。

nattch:谁挂接上了。

status: 状态标识。

2. 删除
ipcrm -m/q/s shmid
3. 挂接
#include <sys/types.h>
#include <sys/shm.h>void *shmat(int shmid,            // shmget的返回值const void *shmaddr,  // 共享内存的起始地址int shmflg            // 权限设置);
4. 断开挂接
#include <sys/types.h>
#include <sys/shm.h>int shmdt(const void *shmaddr // shmat的返回值);

三 demo代码

#include <iostream>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <cstring>// htok 用来形成随机的 key_t
const static std::string pathkey = "/home/CD/linux/shared_memory";
const static int projid = 123456;// 区分创建者和使用者
const static std::string Create = "Create";
const static std::string User = "User";// 共享内存大小
const int shmbuff = 4096;// 转16进制
std::string to_hex(int val)
{char buff[1024] = {0};snprintf(buff, 1024, "0x%x", val);return buff;
}// SHM类
class SHM
{
private:// 进行挂接bool Shmat(){_buff = shmat(_shmid, nullptr, 0);if (_buff == (void *)-1)return false;return true;}// 创建共享内存并获取 shmidbool Createshmid(){_shmid = shmget(_key, shmbuff, IPC_CREAT | IPC_EXCL | 0666);if (_shmid == -1){std::cout << "shmgid create failed" << std::endl;return false;}return true;}// 获取已经存在的共享内存的shmidbool Getshmid(){_shmid = shmget(_key, shmbuff, IPC_CREAT);if (_shmid == -1){std::cout << "shmget get failed" << std::endl;return false;}std::cout << _shmid << std::endl;return true;}public:// 构造对象SHM(const std::string &path, int proj_id, const std::string &who): _path(path), _proj_id(proj_id), _who(who), _buff(nullptr){_key = ftok(_path.c_str(), proj_id);if (_key == -1){std::cout << "ftok failed" << std::endl;exit(-1);}}// 创建共享内存/获取共享内存shmid/挂接共享内存/获取共享内存的起始地址void *run(){if (_who == Create){if (Createshmid() == false)exit(-2);if (Shmat() == false){std::cout << "Shmat failed" << std::endl;exit(-3);}}else{if (Getshmid() == false)exit(-2);if (Shmat() == false){std::cout << "Shmat failed" << std::endl;exit(-3);}}memset(_buff, 0, shmbuff);return _buff;}// 释放共享内存/断开挂起~SHM(){if (_who == Create){int n = shmctl(_shmid, IPC_RMID, nullptr);if (n == -1){std::cout << "ftok failed" << std::endl;exit(-3);}}if (_buff != nullptr)shmdt(_buff);}private:std::string _path;int _proj_id;std::string _who;int _shmid;key_t _key;void *_buff;
};

四 共享内存的特征

1. 由于通信是在用户层直接写到物理内存,没有系统调用,所以不像管道有read/write接口,read的时候没有数据内核会阻塞,而共享内存则没有任何保护机制,也就是无同步无互斥,所以需要应用层进行处理。

2. 共享内存是进程间通信里最快的,用户层直接通过共享映射的虚拟地址写入即可,无任何系统调用。

3. 共享内存的大小是 4k 为基本单位的,不符合倍数就向上取整。

4. 共享内存的生命周期随内核,除非手动代码/指令进行释放。

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

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

相关文章

详解GPU

详解GPU GPU&#xff08;图形处理器&#xff09;就像电脑里的 “图形小能手”&#xff0c;原本主要用来画画&#xff08;渲染图形&#xff09;&#xff0c;现在还能帮忙干很多杂活&#xff08;并行计算&#xff09; 一、先认识 GPU 的 “钥匙”&#xff1a;驱动和开发工具 装驱…

体育遇上AI:解读新一代智能阅读产品

在信息过载的今天&#xff0c;体育迷们时常面对这样的困扰&#xff1a;如何从海量赛事新闻、数据分析和深度评论中高效获取自己真正关心的内容&#xff1f;体育AI阅读产品正成为解决这一痛点的关键钥匙——它融合人工智能技术与体育内容生态&#xff0c;为球迷提供智能化、个性…

外网访问可视化工具 Grafana (Linux版本)

Grafana 是一款强大的可视化监控指标的展示工具&#xff0c;可以将不同的数据源数据以图形化的方式展示&#xff0c;不仅通用而且非常美观。它支持多种数据源&#xff0c;如 prometheus 等&#xff0c;也可以通过插件和 API 进行扩展以满足各种需求。 本文将详细介绍如何在本地…

Java开发经验——阿里巴巴编码规范实践解析4

摘要 本文主要介绍了阿里巴巴编码规范中关于日志处理的相关实践解析。强调了使用日志框架&#xff08;如 SLF4J、JCL&#xff09;而非直接使用日志系统&#xff08;如 Log4j、Logback&#xff09;的 API 的重要性&#xff0c;包括解耦日志实现、统一日志调用方式等好处。同时&…

各个链接集合

golang学习&#xff5e;&#xff5e;_从数组中取一个相同大小的slice有成本吗?-CSDN博客 框架 golang学习&#xff5e;&#xff5e;_从数组中取一个相同大小的slice有成本吗?-CSDN博客 golang k8s学习_容器化部署和传统部署区别-CSDN博客 K8S rabbitmq_rabbitmq 广播-CSD…

Cesium 展示——获取鼠标移动、点击位置的几种方法

文章目录 需求分析:这里我们用到了几种常见的鼠标事件1. 获取鼠标移动的位置2. 获取鼠标点击的位置3. 添加面4. 示例代码需求 获取指定断面的 label 分析:这里我们用到了几种常见的鼠标事件 1. 获取鼠标移动的位置 viewer.screenSpaceEventHandler.setInputAction((moveme…

技术分享 | Oracle SQL优化案例一则

本文为墨天轮数据库管理服务团队第70期技术分享&#xff0c;内容原创&#xff0c;作者为技术顾问马奕璇&#xff0c;如需转载请联系小墨&#xff08;VX&#xff1a;modb666&#xff09;并注明来源。 一、问题概述 开发人员反映有条跑批语句在测试环境执行了很久都没结束&…

$3 #12阶段三小结Java se

$3 #12 阶段三小结 Java se 基本没有新学什么知识点 感觉 基础语法 和高级语法 已经学完了 现在就是得学习 一些企业开发的框架 以及项目架构的思维 比如一个产品 从需求分析 到功能模块设计 到接口文档定义 数据库建立 前端接口页面设计 后端接口开发的步骤 然后现在比…

华为云Flexus+DeepSeek征文 | 初探华为云ModelArts Studio:部署DeepSeek-V3/R1商用服务的详细步骤

华为云FlexusDeepSeek征文 | 初探华为云ModelArts Studio&#xff1a;部署DeepSeek-V3/R1商用服务的详细步骤 前言一、华为云ModelArts Studio平台介绍1.1 ModelArts Studio介绍1.2 ModelArts Studio主要特点1.3 ModelArts Studio使用场景1.4 ModelArts Studio产品架构 二、访问…

易经六十四卦象解释数据集分享!智能体知识库收集~

今天给大家分享一个易经六十四卦象解释数据集 &#xff0c;继续来积累AI相关的资料。 六十四卦&#xff0c;记载于《易经》&#xff0c;每一卦的图像均由两个八卦上下组合而成&#xff0c;每一卦各有六个爻。南宋朱熹说&#xff0c;先画八卦于内&#xff0c;后画八卦于外&#…

1 µs = 10⁻⁶ s

1 s 10⁰ s 1 ms 10⁻ s 1 s 10⁻⁶ s 1 ns 10⁻⁹ s 1 ps 10⁻ s 1 fs 10⁻⁵ s ⏱️ 时间单位&#xff08;十进制&#xff09; 符号单位名称10 的幂次s秒&#xff08;second&#xff09;10⁰ms毫秒&#xff08;millisecond&#xff09;10⁻s微秒&#xff08;microseco…

webrtc初了解

1. webrtc的简介 一、WebRTC 是什么&#xff1f; Web Real-Time Communication&#xff08;网页实时通信&#xff09;&#xff0c;是浏览器原生支持的实时音视频通信技术&#xff0c;无需安装插件或客户端&#xff0c;可直接在浏览器之间实现点对点&#xff08;P2P&#xff09…

从数据持久化到网络通信与OpenCV:Qt应用程序开发的深度探索与实战

文章目录 前言一、QSettings&#xff1a;轻量级数据持久化方案1.1 QSettings 主要特点1.2 QSettings 常用函数整理 二、数据库2.1 连接SQLite数据库2.2 建表2.3 增删改 三、网络编程3.1 网络分层3.2 IP地址3.3 端口号3.4 基于TCP的Socket通信3.4 相关接口3.4.1核心类3.4.2 通信…

经典SQL查询问题的练习第一天

首先有三张表&#xff0c;学生表、课程表、成绩表 student:studentId,studentName; course:courseId&#xff0c;courseName,teacher; score:score,studentId,courseId; 接着有以下几道题目&#xff1a; ①查询课程编号为‘0006’的总成绩&#xff1a; 首先总成绩&#x…

企业级网络管理实战:Linux、云与容器的深度融合与优化

在数字化转型浪潮下&#xff0c;企业网络架构日益复杂&#xff0c;Linux系统、云计算与容器技术成为构建高效、灵活网络的核心要素。本文将从技术原理、实践方案、优化策略三个维度&#xff0c;深度解析企业级网络管理中的关键技术&#xff0c;助力企业打造稳定、安全、可扩展的…

信号与系统速成-1.绪论

b站浙大教授虽然讲的比较细&#xff0c;但是太慢了&#xff0c;不适合速成 祖师爷奥本海姆的MIT课程好像和我们教材的版本不太匹配&#xff0c;但是讲的很不错 慕课上也有很多资源&#xff0c;比如信号与系统 - 网易云课堂 同站博主篱笆外的xixi的文章也挺不错 最终我还是选…

缓存架构方案:Caffeine + Redis 双层缓存架构深度解析

在高并发、低延迟的现代互联网系统中&#xff0c;缓存是提升系统性能和稳定性的重要手段。随着业务复杂度的增长&#xff0c;单一缓存方案&#xff08;如仅使用Redis或仅使用本地缓存&#xff09;已难以满足高性能与一致性需求。 本文将围绕 Caffeine Redis 的双层缓存架构展…

【Elasticsearch】track_total_hits

在 Elasticsearch 中&#xff0c;track_total_hits 是一个查询参数&#xff0c;用于控制是否精确计算搜索结果的总命中数&#xff08;total hits&#xff09;。默认情况下&#xff0c;Elasticsearch 在某些情况下可能会对总命中数进行近似计算&#xff0c;以提高性能。track_to…

智能手机上用Termux安装php+Nginx

Termux的官方网站&#xff1a;Termux | The main termux site and help pages. 以下是在 Termux 上安装和配置 PHP Nginx 的完整流程总结&#xff0c;包含关键步骤和命令&#xff1a; 一、安装依赖 pkg update && pkg upgrade # 更新包列表和系统pkg install nginx p…

电脑开机后出现bootmgr is conmpressed原因及解决方法

最近有网友问我为什么我电脑开机后出现BOOTMGR is compressed&#xff0c;这个提示意思是:意思是启动管理器被压缩了&#xff0c;即使重启也无法正常进入系统。原因有很多&#xff0c;大部分是引导出现问题&#xff0c;或选错了启动硬盘所导致的&#xff0c;下面我们来详细分析…