(26)Linux 进程通信之共享内存(共享储存空间)
共享内存是System V版本的最后一个进程间通信方式。共享内存,顾名思义就是允许两个不相关的进程访问同一个逻辑内存,共享内存是两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常为同一段物理内存。进程可以将同一段物理内存连接到他们自己的地址空间中,所有的进程都可以访问共享内存中的地址。如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。
1、共享内存的通信原理
在Linux中,每个进程都有属于自己的进程控制块(PCB)和地址空间(Addr Space),并且都有一个与之对应的页表,负责将进程的虚拟地址与物理地址进行映射,通过内存管理单元(MMU)进行管理。两个不同的虚拟地址通过页表映射到物理空间的同一区域,它们所指向的这块区域即共享内存。
共享内存原理图:
上图:当两个进程通过页表将虚拟地址映射到物理地址时,在物理地址中有一块共同的内存区,即共享内存,这块内存可以被两个进程同时看到。这样当一个进程进行写操作,另一个进程读操作就可以实现进程间通信。但是,我们要确保一个进程在写的时候不能被读,因此我们使用信号量来实现同步与互斥。
对于一个共享内存,实现采用的是引用计数的原理,当进程脱离共享存储区后,计数器减一,挂架成功时,计数器加一,只有当计数器变为零时,才能被删除。当进程终止时,它所附加的共享存储区都会自动脱离。
2、为什么共享内存速度最快?
借助上图说明:Proc A 进程给内存中写数据, Proc B 进程从内存中读取数据,在此期间一共发生了两次复制
(1)Proc A 到共享内存 (2)共享内存到 Proc B
因为直接在内存上操作,所以共享内存的速度也就提高了。
最简单的共享内存的使用流程
- ①ftok函数生成键值
- ②shmget函数创建共享内存空间
- ③shmat函数获取第一个可用共享内存空间的地址
- ④shmdt函数进行分离(对共享存储段操作结束时的步骤,并不是从系统中删除共享内存和结构)
- ⑤shmctl函数进行删除共享存储空间
3、ftok函数生成键值
每一个共享存储段都有一个对应的键值(key)相关联(消息队列、信号量也同样需要)。
//使用此函数,需导入此头文件
#include <sys/types.h>
#include <sys/ipc.h>key_t ftok(const char *pathname, int proj_id);
- const char *pathname: 一个以null结尾的字符串,表示文件系统中文件的路径。文件应该在调用ftok()时存在。在多个进程中生成相同的键时,需要使用相同的文件路径。
- int proj_id: 一个非零的整数,作为生成键的种子。在多个进程中生成相同的键时,需要使用相同的proj_id。
返回值:成功返回键值(相当于32位的int)。出错返回-1
总之,ftok() 是一个标准C库函数,用于为System V IPC对象生成键。它需要提供文件系统中文件的路径和一个非零整数作为参数。通过使用相同的文件路径和非零整数,可以在多个进程之间生成相同的键,以便共享IPC对象。
例如:key_t key = ftok( “/tmp”, 66);
4、shmget函数创建共享存储空间并返回一个共享存储标识符
所需头文件:#include<sys/shm.h>函数原型: int shmget(key_t key, size_t size, int shmflg);
- [参数key]:由ftok生成的key标识,标识系统的唯一IPC资源。
- [参数size]:需要申请共享内存的大小。在操作系统中,申请内存的最小单位为页,一页是4k字节,为了避免内存碎片,我们一般申请的内存大小为页的整数倍。
- [参数shmflg]:如果要创建新的共享内存,需要使用IPC_CREAT,IPC_EXCL,如果是已经存在的,可以使用IPC_CREAT或直接传0。
- [返回值]:成功时返回一个新建或已经存在的的共享内存标识符,取决于shmflg的参数。失败返回-1并设置错误码。
例如:int id = shmget(key,4096,IPC_CREAT|IPC_EXCL|0666);创建一个大小为4096个字节的权限为0666(所有用户可读可写,具体查询linux权限相关内容)的共享存储空间,并返回一个整形共享存储标识符,如果key值已经存在有共享存储空间了,则出错返回-1。
int id = shmget(key,4096,IPC_CREAT|0666);创建一个大小为4096个字节的权限为0666(所有用户可读可写,具体查询linux权限相关内容)的共享存储空间,并返回一个共享存储标识符,如果key值已经存在有共享存储空间了,则直接返回一个共享存储标识符。
5、shmat 函数:挂接共享内存
//使用此函数,需导入此头文件
#include <sys/types.h>
#include <sys/shm.h>void *shmat(int shmid, const void *shmaddr, int shmflg);
- int shmid: 一个整数,表示共享内存段的标识符(ID)。这个值通常是通过调用 shmget() 函数获得的。
- const void *shmaddr: 一个指针,表示附加共享内存段的首选地址。通常将此参数设置为NULL,让系统自动选择一个合适的地址。
- int shmflg: 一个整数,表示附加共享内存段的标志。常用标志包括:
- SHM_RDONLY: 以只读方式附加共享内存段。
- 0: 以读写方式附加共享内存段。
返回值:
- 成功时,shmat() 返回一个非空指针,表示共享内存段在当前进程地址空间的起始地址。
- 失败时,返回 (void *)-1,并设置相应的 errno。
总之,shmat() 是一个Linux系统调用函数,用于将共享内存段附加到当前进程的地址空间。它需要提供共享内存段的标识符、首选地址和标志作为参数。成功时,它会返回一个指向共享内存段起始地址的指针,用于后续的内存访问操作。
6、shmctl ( ):销毁共享内存
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
- [参数shmid]:共享存储段标识符。
- [参数cmd]:指定的执行操作,设置为IPC_RMID时表示可以删除共享内存。
- [参数*buf]:设置为NULL即可。
- [返回值]:成功返回0,失败返回-1。
7、shmdt函数进行分离
- 当不需要对此共享内存进行操作时候,调用shmdt函数进行分离,不是删除此共享存储空间哟。
- 所需头文件:#include<sys/shm.h>
- 函数原型: int shmdt(const void *addr);
- addr为shmat函数返回的地址指针
- 返回值:成功返回0;错误返回-1
例如:int ret = shmdt(addr);
下面是一个例子,希望对你对上面的内容理解有所帮助。
comm.hpp:
#pragma once#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cassert>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "Log.hpp"using namespace std; //不推荐#define PATH_NAME "/home/whb"
#define PROJ_ID 0x66
#define SHM_SIZE 4096 //共享内存的大小,最好是页(PAGE: 4096)的整数倍#define FIFO_NAME "./fifo"class Init
{
public:Init(){umask(0);int n = mkfifo(FIFO_NAME, 0666);assert(n == 0);(void)n;Log("create fifo success",Notice) << "\n";}~Init(){unlink(FIFO_NAME);Log("remove fifo success",Notice) << "\n";}
};#define READ O_RDONLY
#define WRITE O_WRONLYint OpenFIFO(std::string pathname, int flags)
{int fd = open(pathname.c_str(), flags);assert(fd >= 0);return fd;
}void Wait(int fd)
{Log("等待中....", Notice) << "\n";uint32_t temp = 0;ssize_t s = read(fd, &temp, sizeof(uint32_t));assert(s == sizeof(uint32_t));(void)s;
}void Signal(int fd)
{uint32_t temp = 1;ssize_t s = write(fd, &temp, sizeof(uint32_t));assert(s == sizeof(uint32_t));(void)s;Log("唤醒中....", Notice) << "\n";
}void CloseFifo(int fd)
{close(fd);
}
Log.hpp:
#ifndef _LOG_H_
#define _LOG_H_#include <iostream>
#include <ctime>#define Debug 0
#define Notice 1
#define Warning 2
#define Error 3const std::string msg[] = {"Debug","Notice","Warning","Error"
};std::ostream &Log(std::string message, int level)
{std::cout << " | " << (unsigned)time(nullptr) << " | " << msg[level] << " | " << message;return std::cout;
}#endif
Makefile:
.PHONY:all
all:shmClient shmServershmClient:shmClient.ccg++ -o $@ $^ -std=c++11
shmServer:shmServer.ccg++ -o $@ $^ -std=c++11
.PHONNY:clean
clean:rm -f shmClient shmServer
shmServer.cc:
#include "comm.hpp"// 是不是对应的程序,在加载的时候,会自动构建全局变量,就要调用该类的构造函数 -- 创建管道文件
// 程序退出的时候,全局变量会被析构,自动调用析构函数,会自动删除管道文件
Init init; string TransToHex(key_t k)
{char buffer[32];snprintf(buffer, sizeof buffer, "0x%x", k);return buffer;
}int main()
{// 我们之前为了通信,所做的所有的工作,属于什么工作呢:让不同的进程看到了同一份资源(内存)// 1. 创建公共的Key值key_t k = ftok(PATH_NAME, PROJ_ID);assert(k != -1);Log("create key done", Debug) << " server key : " << TransToHex(k) << endl;// 2. 创建共享内存 -- 建议要创建一个全新的共享内存 -- 通信的发起者int shmid = shmget(k, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0666); //if (shmid == -1){perror("shmget");exit(1);}Log("create shm done", Debug) << " shmid : " << shmid << endl;// sleep(10);// 3. 将指定的共享内存,挂接到自己的地址空间char *shmaddr = (char *)shmat(shmid, nullptr, 0);Log("attach shm done", Debug) << " shmid : " << shmid << endl;// sleep(10);// 这里就是通信的逻辑了// 将共享内存当成一个大字符串// char buffer[SHM_SIZE];// 结论1: 只要是通信双方使用shm,一方直接向共享内存中写入数据,另一方,就可以立马看到对方写入的数据。// 共享内存是所有进程间通信(IPC),速度最快的!不需要过多的拷贝!!(不需要将数据给操作系统)// 结论2: 共享内存缺乏访问控制!会带来并发问题 【如果我想一定程度的访问控制呢? 能】int fd = OpenFIFO(FIFO_NAME, READ);for(;;){Wait(fd);// 临界区printf("%s\n", shmaddr);if(strcmp(shmaddr, "quit") == 0) break;// sleep(1);}// 4. 将指定的共享内存,从自己的地址空间中去关联int n = shmdt(shmaddr);assert(n != -1);(void)n;Log("detach shm done", Debug) << " shmid : " << shmid << endl;// sleep(10);// 5. 删除共享内存,IPC_RMID即便是有进程和当下的shm挂接,依旧删除共享内存n = shmctl(shmid, IPC_RMID, nullptr);assert(n != -1);(void)n;Log("delete shm done", Debug) << " shmid : " << shmid << endl;CloseFifo(fd);return 0;
}
shmClient.cc:
#include "comm.hpp"int main()
{Log("child pid is : ", Debug) << getpid() << endl;key_t k = ftok(PATH_NAME, PROJ_ID);if (k < 0){Log("create key failed", Error) << " client key : " << k << endl;exit(1);}Log("create key done", Debug) << " client key : " << k << endl;// 获取共享内存int shmid = shmget(k, SHM_SIZE, 0);if(shmid < 0){Log("create shm failed", Error) << " client key : " << k << endl;exit(2);}Log("create shm success", Error) << " client key : " << k << endl;// sleep(10);char *shmaddr = (char *)shmat(shmid, nullptr, 0);if(shmaddr == nullptr){Log("attach shm failed", Error) << " client key : " << k << endl;exit(3);}Log("attach shm success", Error) << " client key : " << k << endl;// sleep(10);int fd = OpenFIFO(FIFO_NAME, WRITE);// 使用// client将共享内存看做一个char 类型的bufferwhile(true){ssize_t s = read(0, shmaddr, SHM_SIZE-1);if(s > 0){shmaddr[s-1] = 0;Signal(fd);if(strcmp(shmaddr,"quit") == 0) break;}}CloseFifo(fd);// 去关联int n = shmdt(shmaddr);assert(n != -1);Log("detach shm success", Error) << " client key : " << k << endl;// sleep(10);// client 要不要chmctl删除呢?不需要!!return 0;
}
相关文章:
(26)Linux 进程通信之共享内存(共享储存空间)
共享内存是System V版本的最后一个进程间通信方式。共享内存,顾名思义就是允许两个不相关的进程访问同一个逻辑内存,共享内存是两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常为同一段物理内存。进程可以将同一…...
体感游戏开发体感互动游戏
体感健身游戏是一种利用特定技术来跟踪和响应玩家身体动作的互动式电子游戏。这种游戏类型的目的是通过有趣、动态的方式鼓励用户进行身体活动和健康锻炼。下面是有关体感健身游戏的一些重要信息: 体感游戏技术背景 体感技术:这些游戏通常使用运动传感…...
vulnhub靶场之DC-5
一.环境搭建 1.靶场描述 DC-5 is another purposely built vulnerable lab with the intent of gaining experience in the world of penetration testing. The plan was for DC-5 to kick it up a notch, so this might not be great for beginners, but should be ok for p…...
为什么选择CRM系统时,在线演示很重要?
想要知道一款CRM管理系统是否满足企业的需求,操作是否简单,运行是否流畅,最直观的方式就是远程演示。否则,光凭厂商的销售人员介绍一下产品,企业就盲目下单,最后发现功能不匹配,还要赔钱赔时间重…...
专业实习day3、4(路由器做内网访问公网)
专业实习 代码 display ip interface brief 显示当前设备下所有接口IP undo IP地址支持覆盖,但是正常的命令不能覆盖必须undo(删除)掉 un in en 在做配置的过程中,设备系统一般都会出现一些提示或者告警之类的东西,从…...
H264码流进行RTP包封装
一.H264基本概念 H.264从框架结构上分为视频编码层(VCL)和网络抽象层(NAL),VCL功能是进行视频编解码,包括运动补偿预测,变换编码和熵编码等功能;NAL用于采用适当的格式对VCL视频数据…...
基于多智能体点对点转换的分布式模型预测控制
matlab2020正常运行 基于多智能体点对点转换的分布式模型预测控制资源-CSDN文库...
性能分析与调优: Linux 实现 缺页剖析与火焰图
目录 一、实验 1.环境 2.缺页(RSS增长)剖析与火焰图 一、实验 1.环境 (1)主机 表1-1 主机 主机架构组件IP备注prometheus 监测 系统 prometheus、node_exporter 192.168.204.18grafana监测GUIgrafana192.168.204.19agent 监测 主机 node_exporter…...
代码随想录算法训练营第17天 | 110.平衡二叉树 + 257. 二叉树的所有路径 + 404.左叶子之和
今日内容 110.平衡二叉树 257. 二叉树的所有路径 404.左叶子之和 110.平衡二叉树 - Easy 题目链接:. - 力扣(LeetCode) 给定一个二叉树,判断它是否是高度平衡的二叉树。 本题中,一棵高度平衡二叉树定义为࿱…...
ubuntu20.04网络问题以及解决方案
1.网络图标消失,wired消失,ens33消失 参考:https://blog.51cto.com/u_204222/2465609 https://blog.csdn.net/qq_42265170/article/details/123640669 原始是在虚拟机中切换网络连接方式(桥接和NAT), 解决…...
Java面试题(java高级面试题)
线程池的核心线程数设置为多大比较合理? Worker线程在执行的过程中,有一部计算时间需要占用CPU,另一部分等待时间不需要占用CPU,通过量化分析,例如打日志进行统计,可以统计出整个Worker线程执行过程中这两…...
【MIdjourney】关于图像中人物视角的关键词
本篇仅是我个人在使用过程中的一些经验之谈,不代表一定是对的,如有任何问题欢迎在评论区指正,如有补充也欢迎在评论区留言。 1.全景镜头(panorama) 全景镜头是一种广角镜头,可以捕捉到比普通镜头更广阔的视野范围。全景镜头&…...
433. 最小基因变化(Queue使用ArrayList和LinkedList进行声明)
这道题可以看成一个24叉树。 因为基因序列长度固定为8,且每个位置的字母固定是AGCT,可以选择改变的只有3个字母,所以一次最多24种情况。 然后检查变化后的结果是否存在bank中(使用hashSet来存储),同时设置…...
MYSQL双主节点–更换ip
MYSQL双主节点–更换ip 一、更换双主节点ip 1.停止mysql服务 #安装了supervisor supervisorctl stop mysql #未安装 systemctl stop mysqld2.修改网卡配置信息 注:ens33是网卡名称,可能网卡不叫ens33 vi /etc/sysconfig/network-scripts/ifcfg-ens333…...
一文玩转Go语言中的面向对象编程~
温故而知新:什么是面向对象 面向对象(Object-Oriented)是一种计算机编程的方法和思想,它将程序中的数据(对象)和操作(方法)组织成一个个相互关联和交互的对象。对象是现实世界中的事…...
kylin集群反向代理(健康检查)
前面一篇文章提到了使用nginx来对kylin集群进行反向代理, kylin集群使用nginx反向代理-CSDN博客文章浏览阅读349次,点赞8次,收藏9次。由于是同一个集群的,元数据没有变化,所以,直接将原本的kylin使用scp的…...
【docker】centos7安装harbor
目录 零、前提一、下载离线包二、安装三、访问四、开机自启 零、前提 1.前提是已经安装了docker和docker-compose 一、下载离线包 1. csdn资源:harbor-offline-installer-v2.10.0.tgz 2. 百度云盘(提取码:ap3t):harbo…...
2024 年 1 月安全更新修补了 58 个漏洞(Android )
谷歌发布了针对 Android 平台 58 个漏洞的补丁,并修复了 Pixel 设备中的 3 个安全漏洞,拉开了 2024 年的序幕。 Android 2024 年 1 月更新的第一部分以 2024 年 1 月 1 日安全补丁级别发布在设备上,解决了框架和系统组件中的 10 个安全漏洞&…...
数据库系统概念 第七版 中文答案 第3章 SQL介绍
3.1 将以下查询使用SQL语言编写,使用大学数据库模式。 (我们建议您实际在数据库上运行这些查询,使用我们在书籍网站db-book.com上提供的示例数据。有关设置数据库和加载示例数据的说明,请参阅上述网站。) a. 查找计算机…...
什么是数通技术?以太网交换机在数通技术中的精要
什么是数通技术? 数通技术是指数字通信技术,它涵盖了数字信号处理、数据传输、网络通信等领域。通信工程师在数通技术中负责设计、建设和维护数字通信系统,以实现可靠、高效的信息传输。这涉及到数字信号的编解码、调制解调、数据压缩、网络…...
php 的数学常用函数
目录 1.常用列表 2.代码示例 1.常用列表 函数名描述输入输出abs()求绝对值数字绝对值数字ceil()进一法取整浮点数进一取整floor()舍去法求整浮点数直接舍去小数部分fmod()浮点数取余 两个浮点 数,x>y 浮点余数 pow()返回数的n次方基础数n次方乘方值round()浮点数四舍五入…...
Netty-Netty组件了解
EventLoop 和 EventLoopGroup 回想一下我们在 NIO 中是如何处理我们关心的事件的?在一个 while 循环中 select 出事 件,然后依次处理每种事件。我们可以把它称为事件循环,这就是 EventLoop 。 interface io.netty.channel. EventLoo…...
银行的压力测试如何进行?
为什么要进行压力风险测试? 压力风险测试的最终目的是测试银行在极度恶劣的市场环境中是否有足够的资本维持运转。 题主链接中的一级资本充足率(Tier 1 capital ratio) 亦即衡量标准,这个数字越大,表明银行资本约充裕,可以在停止…...
QtService、托盘程序使用
1、QtService 使用QtService实现Qt后台服务程序 用QT创建一个Windows Service以及踩到的若干坑 2、托盘程序 Qt之程序最小化托盘显示及操作 Qt系统托盘程序的实现...
使用Linux防火墙管理HTTP流量
在Linux系统中,防火墙是用于控制网络流量的重要工具。通过防火墙,你可以根据需要限制、过滤或允许特定的网络流量,从而提高系统的安全性。在处理HTTP流量时,防火墙可以帮助你实施访问控制、流量监控和其他安全策略。 iptables i…...
图鸟引入多套字体图标的方式教程
https://www.yuque.com/tuniao/qunyou/tgfvpg ①上传icon,生成iconfont.css 将css文件放这里 app.vue全局引入 适当改造iconfont.css的写法,方便调用...
在openEuler环境下快速编译GreatSQL RPM包
在上一篇中,已经介绍了在CentOS环境下编译GreatSQL RPM包的过程,本文再介绍如何在openEuler环境下编译GreatSQL RPM包。 运行环境是docker中的openEuler 22.03 x86_64: $ docker -v Docker version 20.10.10, build b485636$ docker run -itd…...
C语言基础语法跟练 day3
31、不使用累计乘法的基础上,通过移位运算(<<)实现2的n次方的计算。 #include <stdio.h> int main() {int i 0;scanf("%d",&i);printf("%d",1<<i);return 0; } 32、问题:一年约有 3.…...
【控制篇 / 策略】(7.4) ❀ 01. IP地理位置数据库和地理地址对象 ❀ FortiGate 防火墙
【简介】在很多使用环境下,我们需要对指定国家的IP地址进行允许或禁止访问操作,例如只允许访问国内IP。以前只能手动添加IP地址对象到地址组,繁杂且效率低下,Fortinet提供了基于地理位置的IP库,就可以解决这个问题。 I…...
NX二次开发点通过云配准获取相同体
先找到体的参考方向(这个参考方向对于相同体重合之后是相同的),这个时候我们的思路是三个不共线的点确定一个坐标系,然后和绝对方向求转换矩阵。然后获取体的所有边的几何中心,把这些点通过转换矩阵转换之后存起来&…...
网站建设费用/凡科网站建站教程
数组有四种定义的方式 使用构造函数: var a new Array(); var b new Array(8); var c new Array("first", "second", "third"); 或者数组直接量: var d ["first", "second", "third"];…...
wordpress分类规则/优化关键词的正确方法
计算机科学硕士MS/MCS. Computer Science是弗吉尼亚大学研究生申请的热门专业,下面由美英港新教育重点介绍计算机科学硕士研究生的课程设置、培养目标、申请要求及学费。培养目标计算机科学:在计算方面取得进步,推动人类努力的各个方面取得进…...
如何做企业介绍/云速seo百度点击
2019独角兽企业重金招聘Python工程师标准>>> Redis的事务 是什么Redis的事务 可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞噢:&…...
网站信息安全建设方案/网络营销平台的主要功能
计算机视觉的研究领域 图像分类 语义分割 分类和定位 目标检测 实例分割 人脸识别 生成模型 风格迁移 物体跟踪 图像问答 转载于:https://www.cnblogs.com/kexinxin/p/9858556.html...
电子商务网站设计是什么/连云港seo优化公司
经常有新手配置基于svnserve的subversion服务器后,在客户端访问subversion版本库时出现这个错误:svnserve.conf:12: Option expected为什么会出现这个错误呢,就是因为subversion读取配置文件svnserve.conf时,无法识别有前置空格的…...
网页和网站的联系/学seo哪个培训好
Toy Posted in Apps, IDECobras 是次要专注于行使 Qt 的集成开辟环境(IDE),它宣布在 GNU GPL 允许和谈之下,仅需求 gcc 和 gdb 作为内部东西,程序功用厚实,且运转不乱而疾速。行使 Qt 从事软件开辟的冤家没…...