【linux--进程通信之共享内存】

目录

  • 一、共享内存的原理
  • 二、共享内存的数据结构
  • 三、共享内存使用的函数
    • 2.1ftok函数
    • 2.2shmget函数
    • 2.3shmctr函数
    • 2.4shmat函数
    • 2.5shmdt函数
  • 四、实现进程通信

一、共享内存的原理

共享内存实际是操作系统在实际物理内存中开辟的一段内存。
共享内存实现进程间通信,是操作系统在实际物理内存开辟一块空间,一个进程在自己的页表中,将该空间和进程地址空间上的共享区的一块地址空间形成映射关系。另外一进程在页表上,将同一块物理空间和该进程地址空间上的共享区的一块地址空间形成映射关系。
当一个进程往该空间写入内容时,另外一进程访问该空间,会得到写入的值,即实现了进程间的通信。
注意:共享内存实现进程间通信是进程间通信最快的。(相比较管道共享内存不需要两次拷贝)
在这里插入图片描述

二、共享内存的数据结构

在系统当中可能会有大量的进程在进行通信,因此系统当中就可能存在大量的共享内存,那么操作系统必然要对其进行管理,所以共享内存除了在内存当中真正开辟空间之外,为了维护管理共享内存,系统一定要"描述"共享内存

/* Obsolete, used only for backwards compatibility and libc5 compiles */
struct shmid_ds {
	struct ipc_perm		shm_perm;	/* operation perms */
	int			shm_segsz;	/* size of segment (bytes) *///共享内存空间大小
	__kernel_time_t		shm_atime;	/* last attach time *///挂接时间
	__kernel_time_t		shm_dtime;	/* last detach time *///取消挂接时间
	__kernel_time_t		shm_ctime;	/* last change time *///改变时间
	__kernel_ipc_pid_t	shm_cpid;	/* pid of creator */
	__kernel_ipc_pid_t	shm_lpid;	/* pid of last operator */
	unsigned short		shm_nattch;	/* no. of current attaches *///进程挂接数
	unsigned short 		shm_unused;	/* compatibility */
	void 			*shm_unused2;	/* ditto - used by DIPC */
	void			*shm_unused3;	/* unused */
};

描述共享内存的数据结构里保存了一个ipc_perm结构体,这个结构体保存了IPC(进程将通信)的关键信息。

/* Obsolete, used only for backwards compatibility and libc5 compiles */
struct ipc_perm
{
	__kernel_key_t	key;//共享内存的唯一标识符
	__kernel_uid_t	uid;
	__kernel_gid_t	gid;
	__kernel_uid_t	cuid;
	__kernel_gid_t	cgid;
	__kernel_mode_t	mode; //权限
	unsigned short	seq;
};

三、共享内存使用的函数

2.1ftok函数

在这里插入图片描述

  • 参数:第一个是地址,第二个是至少8位的项目id,不能为0,两参数可以是任意值,但是要符合格式。
  • 返回值:ftok如果成功返回一个key值,如果失败返回-1。如果失败了再重新填写参数即可。
  • 作用:算出一个唯一的key返回。

ftok中的参数可以随便填写,但是要符合格式,ftok只是利用参数,再运用一套算法,算出一个唯一的key值返回。这个key值可以传给共享内存参数,作为struct
ipc_perm中唯一标识共享内存的key。

2.2shmget函数

在这里插入图片描述

  • 参数:
    key:为共享内存的名字,一般是ftok的返回值。 size:共享内存的大小,以page为单位,大小为4096的整数倍。
    shmflg:权限标志,常用两个IPC_CREAT和IPC_EXCL,一般后面还加一个权限,相当于文件的权限。
    IPC_CREAT:创建一个共享内存返回,已存在打开返回
    IPC_EXCL:配合着IPC_CREAT使用,共享内存已存在出错返回。
    使用:IPC_CREAT | IPC_EXCL | 0666
  • 返回值:
    成功返回一个非负整数,即共享内存的标识码,失败返回-1。
  • 作用:创建一个共享内存
    为什么已经有一个key来标识共享内存,还需要一个返回值来标识共享内存?因为key是内核级别的,供内核标识,shmget返回值是用户级别的,供用户使用的。
    command.hpp
#include<iostream>
using namespace std;
#include<sys/types.h>     
#include<sys/ipc.h>  
#include<sys/shm.h>
#define PATHNAME "/home/zuofangting"
#define PROJ_ID 0x888
#define SIZE 4096
key_t GetKey()
{ 
    key_t ret=ftok(PATHNAME,PROJ_ID);
    if(ret==-1) return -1;
    cout<<"key:"<<ret<<endl;
    return ret;
}

int GetShmget()
{
    key_t key=GetKey();
    int shmid=shmget(key,SIZE,IPC_CREAT | IPC_EXCL | 0666);
    if(shmid==-1)
    {
        cout<<"GetShmget fail"<<endl;
        return -1;
    }
    cout<<"shmid:"<<shmid<<endl;
    return shmid;
}

processa.cc

#include"command.hpp"
int main()
{
    GetShmget();

    return 0;
}

现象:
在这里插入图片描述
注意:IPC(进程将通信)资源生命周期不随进程,而是随内核的,不释放会一直占用,除非重启。所以,shmget创建的共享内存要释放掉,不然会内存泄漏。如图:
在这里插入图片描述
可以用命令行来释放共享内存**:ipcrm -m shmid**(shmget返回值)
在这里插入图片描述

2.3shmctr函数

在这里插入图片描述

  • 作用:用于控制共享内存
  • 参数:
    shmid:共享内存的标识
    cmd:以什么方式来控制共享内存。IPC_RMID是释放共享内存
    buf:指向一个共享内存的数据结构 。struct shmid_ds
  • 返回值:成功返回0,失败返回-1。
    使用样例代码:
  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/ipc.h>
  4 #include<sys/shm.h>
  5 #include"com.h"
  6 
  7 int main(){
  8   key_t k = ftok(PATHNAME,PROJ_ID);//获取一个唯一标识符key
  9   if(k==-1){
 10     perror("ftok error");
 11     return 1;
 12   }
 13 
 14   printf("ftok : %d\n",k);
 15 
 16   int shmid = shmget(k,SIZE,IPC_CREAT | IPC_EXCL | 0666);//创建共享内存
 17   if(shmid == -1){
 18     perror("shmget error");
 19     return 1;
 20   }
 21   printf("shmid : %d\n",shmid);
 22 
 23   int sh = shmctl(shmid,IPC_RMID,NULL);//删除共享内存
 24   if(sh == -1){                                                                                                                                          
 25     perror("shmctl");
 26     return 1;
 27   }
 28   return 0;
 29 }

2.4shmat函数

在这里插入图片描述

  • 作用:使创建的共享内存与调用该函数进程的进程地址空间参数关联。
  • 参数:
    shmid:共享内存的标识,shmget的返回值。
    shmaddr:指定进程地址空间连接的地址。如果设置为null,默认让系统定要关联的地址。
    shmflg:权限,常见有两个SHM_RDONLY(只读)和SHM_REMAP(重新映射一个进程地址空间没这样shmaddr不能为空)。设为0,系统默认。
  • 返回值:返回映射到进程地址空间共享区的开始地址。

2.5shmdt函数

在这里插入图片描述
作用:删除共享内存与进程地址空间的映射关系,将页表映射关系删除,释放进程地址空间。

  • 参数:

     shmaddr:共享内存映射到进程地址空间的地址。shmat返回值。
    
  • 返回值:

     成功返回0,失败返回-1
    

四、实现进程通信

makefile

  .PHONY:all
all:processa processb
processa:processa.cc
	g++ -o $@ $^ -std=c++11
processb:processb.cc
	g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
	rm -f processa processb

command.hpp

#include<iostream>
using namespace std;
#include<string.h>
#include<sys/types.h>     
#include<sys/ipc.h>  
#include<sys/shm.h>
#include<unistd.h>
#define PATHNAME "/home/zuofangting"
#define PROJ_ID 0x888
#define SIZE 4096

key_t GetKey()
{ 
    key_t ret=ftok(PATHNAME,PROJ_ID);
    if(ret==-1) return -1;
    cout<<"key:"<<ret<<endl;
    return ret;
}

int GetShmget(int flag)
{
    key_t key=GetKey();
    int shmid=shmget(key,SIZE,flag);
    if(shmid==-1)
    {
        cout<<"GetShmget fail"<<endl;
        return -1;
    }
    cout<<"shmid:"<<shmid<<endl;
    return shmid;
}

int CreateShm()
{
    return GetShmget(IPC_CREAT | IPC_EXCL | 0666);
}

int GetShm()
{
    return GetShmget(IPC_CREAT);
}

processa.cc

#include"command.hpp"
int main()
{
    //创建共享内存
    int shmid=CreateShm();

    //挂接
    char *shmaddr=(char*)shmat(shmid,nullptr,0);

    //通信
    while(true)
    {
        cout<<"client@:"<<shmaddr<<endl;
    }

    //去挂接
    int ret=shmdt(shmaddr);

    //释放共享内存
    shmctl(shmid,IPC_RMID,nullptr);

    return 0;
}

processb.cc

#include"command.hpp"
int main()
{
    //创建共享内存
    int shmid=GetShm();

    //挂接
    char *shmaddr=(char*)shmat(shmid,nullptr,0);

    //通信
    while(true)
    {
        char buffer[1024];
        cout<<"please enter";
        fgets(buffer,sizeof(buffer),stdin);
        memcpy(shmaddr,buffer,strlen(buffer)+1);

    }

    //去挂接
    int ret=shmdt(shmaddr);

    return 0;
}

共享内存实现的进程间通信底层不提供任何同步与互斥机制。如果想让两进程很好的合作起来,在IPC里要有信号量来支撑。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

华为云创新动能涌现,浒墅关开启先进制造新纪元

编辑&#xff1a;阿冒 设计&#xff1a;沐由 穿境而过的京杭大运河&#xff0c;孕育了苏州浒墅关深厚的历史文化底蕴。千年延续不断的繁华&#xff0c;滋养了一代又一代奋进的浒墅关人。今天&#xff0c;一座国家级经开区挺立在这里&#xff0c;散发出创新创业的蓬勃活力。 苏州…

配置本地端口镜像示例

镜像概念 定义 镜像是指将指定源的报文复制一份到目的端口。指定源被称为镜像源&#xff0c;目的端口被称为观察端口&#xff0c;复制的报文被称为镜像报文。 镜像可以在不影响设备对原始报文正常处理的情况下&#xff0c;将其复制一份&#xff0c;并通过观察端口发送给监控…

dysmsapi

dysmsapi DY - SMS - API 短信服务接口 短信服务_SDK中心-阿里云OpenAPI开发者门户 <!-- 阿里dayu sms api短信群发接口 --><!-- https://mvnrepository.com/artifact/com.aliyun/dysmsapi20170525/2.0.24 --><dependency><groupId>com.aliyun&l…

WEB渗透—PHP反序列化(三)

Web渗透—PHP反序列化 课程学习分享&#xff08;课程非本人制作&#xff0c;仅提供学习分享&#xff09; 靶场下载地址&#xff1a;GitHub - mcc0624/php_ser_Class: php反序列化靶场课程&#xff0c;基于课程制作的靶场 课程地址&#xff1a;PHP反序列化漏洞学习_哔哩…

07用户行为日志数据采集

用户行为数据由Flume从Kafka直接同步到HDFS&#xff0c;由于离线数仓采用Hive的分区表按天统计&#xff0c;所以目标路径要包含一层日期。具体数据流向如下图所示。 按照规划&#xff0c;该Flume需将Kafka中topic_log的数据发往HDFS。并且对每天产生的用户行为日志进行区分&am…

【学习笔记】JavaScript中的GC算法

1、内存管理 内存&#xff1a;由可读写单元组成&#xff0c;标识一片可操作的空间 管理&#xff1a; 认为的去操作一篇空间的申请、使用和释放 内存管理&#xff1a;开发者主动申请空间、使用空间、释放空间 管理流程&#xff1a; 申请-使用-释放 // 申请 let obj {} //使…

java代理模式

1.定义:一个对象要访问另外一个对象 通过一个中间对象&#xff0c;像一个中介 2.类图 一个抽象类 一个代理类 一个真实调用对象类 3.代理模式 4.符合开闭原则 可以新创建代理类 来满足不通的情况 例如不同等级的账号拥有的权限不同 5.总结 6.类似springAOP

遗传算法应用-- 栅格法机器人路径规划

文章目录 一、遗传算法1.1 编码与解码1.2 选择算子-轮盘赌法1.3 交叉算子1.4 变异算子1.5 遗传算法流程1.6 基于遗传算法的栅格法机器人路径规划 二、采用模拟退火算法改善适应度函数 一、遗传算法 遗传算法 (Genetic AIgorithm, 简称 GA)起源于对生物系统所进行的计算机模拟研…

DC电源模块的设计与制造技术创新

BOSHIDA DC电源模块的设计与制造技术创新 DC电源模块的设计与制造技术创新主要涉及以下几个方面&#xff1a; 1. 高效率设计&#xff1a;传统的DC电源模块存在能量转换损耗较大的问题&#xff0c;技术创新可通过采用高效率的电路拓扑结构、使用高性能的功率开关器件和优化控制…

HarmonyOS云开发基础认证考试满分答案(100分)【全网最全-不断更新】【鸿蒙专栏-29】

系列文章&#xff1a; HarmonyOS应用开发者基础认证满分答案&#xff08;100分&#xff09; HarmonyOS应用开发者基础认证【闯关习题 满分答案】 HarmonyOS应用开发者高级认证满分答案&#xff08;100分&#xff09; HarmonyOS云开发基础认证满分答案&#xff08;100分&#xf…

动态规划——OJ题(一)

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、第N个泰波那契数1、题目讲解2、思路讲解3、代码实现 二、三步问题1、题目讲解2、思路讲解…

PyCharm community 安装教程

目录 链接cudatoolkit 下载地址&#xff1a;https://www.jetbrains.com/pycharm/download/other.html 双击打开 安装路径&#xff0c;可自行更换到D盘 不导入设置 链接cudatoolkit

英伟达盒子 Jetson Xshell连接串口查看日志方法(串口日志、盒子日志)

文章目录 连接串口xshell连接串口信息 连接串口 接盒子上的A2、B2&#xff0c;以及接地线&#xff1a; 另外一头接上电脑&#xff08;我用的RS485转USB工具&#xff09;&#xff1a; xshell连接 协议选择SERIAL&#xff1a; 设置盒子厂商约定的端口号、波特率、数据位、停止位…

[Verilog] Verilog 数值表示

主页&#xff1a; 元存储博客 文章目录 前言1. 整数表示1.1 整数数据类型1.2 整数转换函数 2. 负数表示3. 实数表示4. 逻辑电平表示5. 逻辑值表示6. 字符表示法7. 字符串表示 前言 Verilog中&#xff0c;可以使用多种方式表示数值。 1. 整数表示 1.1 整数数据类型 基数格式…

相机倾斜棋盘格标定全记录 vs200+opencv安装

论文参考是这个 Geiger A, Moosmann F, Car , et al. Automatic camera and range sensor calibration using a single shot[C]//Robotics and Automation (ICRA), 2012 IEEE International Conference on. IEEE, 2012: 3936-3943. 代码是这个github 花了一上午配好了c环境。。…

AAAI中稿心得

很幸运我们的一篇工作中稿了AAAI2024&#xff0c;题目是 Self-Prompt Mechanism for Few-Shot Image Recognition. 很高兴能在研二的上学期中稿一篇a会保底&#xff0c;也是我中稿的第一篇工作&#xff0c;成为我申请博士的资本。最重要的是&#xff0c;让枯燥无味的科研&#…

linux串口数据丢失--中断绑定CPU优化

问题现象 机器在户外测试时, 出现 轮速记 丢失的现象 小概率出现 50Hz丢失1~2帧极低概率出现 0.1~0.3秒内没有底盘数据 此问题导致slam定位漂, 需要优化处理. 验证与测试 问题1: 底盘串口 一个数据帧(head–data–crc) 被分片2~3报文 解决方法: 检测到head之后, 解析data…

机器学习--归一化处理

归一化 归一化的目的 归一化的一个目的是&#xff0c;使得梯度下降在不同维度 θ \theta θ 参数&#xff08;不同数量级&#xff09;上&#xff0c;可以步调一致协同的进行梯度下降。这就好比社会主义&#xff0c;一小部分人先富裕起来了&#xff0c;先富带后富&#xff0c…

03 使用Vite开发Vue3项目

概述 要使用vite创建Vue3项目&#xff0c;有很多种方式&#xff0c;如果使用命令&#xff0c;则推荐如下命令&#xff1a; # 使用nvm将nodejs的版本切换到20 nvm use 20# 全局安装yarn npm install -g yarn# 使用yarnvite创建项目 yarn create vite不过&#xff0c;笔者更推荐…

docker小白第五天

docker小白第五天 docker的私有库 有些涉密的信息代码不能放在阿里云的镜像仓库&#xff0c;因此需要构建一个个人内网专属的私有库&#xff0c;将镜像或者容器代码进行推送保存。 下载镜像docker registry 执行代码docker pull registry&#xff0c;用于搭建私服前的准备。…