【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);//获取一个唯一标识符key9   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.ccg++ -o $@ $^ -std=c++11
processb:processb.ccg++ -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 4096key_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里要有信号量来支撑。

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

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

相关文章

大数据之如何利用爬虫爬取数据做分析

目录 前言 爬虫概述 爬虫实现 1. 获取代理IP 2. 爬取数据 3. 多线程爬取 总结 前言 随着互联网和智能设备的普及&#xff0c;数据量逐年增长&#xff0c;数据分析和挖掘成为了热门领域&#xff0c;其中大数据分析技术和爬虫技术是重要的手段之一。本文主要介绍如何使用…

Python框架批量数据抓取的高级教程

一、背景介绍 批量数据抓取是一种常见的数据获取方式&#xff0c;能够帮助我们快速、高效地获取网络上的大量信息。本文将介绍如何使用Python框架进行大规模抽象数据&#xff0c;以及如何处理这个过程中可能遇到的问题。 二、项目需求 我们将爬取大量知乎文章&#xff0c;讨…

扁平化菜单功能制作

网页效果&#xff1a; HTML部分&#xff1a; <body><ul class"nav"><li><a href"javascript:void(0);">菜单项目一</a><ul><li>子菜单项01</li><li>子菜单项02</li><li>子菜单项03<…

matlab面向对象编程入门笔记

文章目录 1. 类和结构2. 定义类3. 属性3.1 private/protected/public属性3.2 constant属性3.3 hidden属性 4. 方法4.1 private/protected/public方法4.2 static方法4.3 外部方法 5. 动态调用6. 继承-超类6.1 handle超类6.2 dynamicprops 和 hgsetget子类 7. 封闭(sealed)类、方…

波奇学Linux:Linux进程状态,进程优先级

编写一个程序模拟进程 查看进程状态 修改代码后发现进程状态为由S变成R R为运行态&#xff0c;S为阻塞态 第一次为S是因为调用了外设&#xff08;printf调用屏幕外设&#xff09;&#xff0c;实际上应该为R&#xff0c;S状态轮换&#xff0c;但是R太快了&#xff0c;所以每次…

性能测试之Locust(完整版)

官方文档&#xff1a;Locust说明文档 一、Locust简介 1、定义 Locust是一款易于使用的分布式负载测试工具&#xff0c;完全基于事件&#xff0c;即一个locust节点也可以在一个进程中支持数千并发用户&#xff0c;不使用回调&#xff0c;通过gevent使用轻量级过程&#xff08…

订单管理系统开发经验的总结:优化流程、提升效率的关键实践

前言 一.订单管理系统的架构设计 二.订单系统的详细设计 1.拆分 2.换货 3.发货 4.拦截 5.取消 6.物流回传 三.订单系统的订单状态流转 初始状态 中间状态 异常状态 终态 四.订单系统的关键代码逻辑 五.结语 前言 两年来&#xff0c;整个订单管理系统经过大大小…

序列生成模型(一):序列概率模型

文章目录 前言1. 序列数据2. 序列数据的潜在规律3. 序列概率模型的两个基本问题 一、序列概率模型1. 理论基础序列的概率分解自回归生成模型 2. 序列生成 前言 深度学习在处理序列数据方面取得了巨大的成功&#xff0c;尤其是在自然语言处理领域。序列数据可以是文本、声音、视…

【算法Hot100系列】三数之和

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

人生感悟 | 又是一年,眼看要2024了

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 刚过完大雪节气没两天&#xff0c;气温开始急转直下&#xff0c;走在路上明显感觉冷了许多。看天气预报很多地区已经开始下雪了。 看日历已经12月9号了&#xff0c;12月份&#xff0c;一年的最后一个月&#xff0c;2…

别小看Python的【print】函数,这些高级用法你知道吗?

文章目录 引言技巧1&#xff1a;格式化输出示例1&#xff1a;使用%s来插入字符串&#xff0c;使用%d来插入整数示例2&#xff1a;使用字符串的format()方法示例3&#xff1a;使用f-string格式化输出 技巧2&#xff1a;控制输出文本的颜色技巧3&#xff1a;将打印结果重定向至文…

PyVMomi 克隆虚拟机时将磁盘改为Thin模式

需求介绍&#xff1a; 之前已经使用pyvmomi库实现了虚拟机的自动备份&#xff0c;不过由于备份的虚拟机都是较为重要的系统&#xff0c;磁盘都是厚置备模式&#xff0c;终于有一天&#xff0c;备份目标的空间不够了&#xff0c;导致几个虚拟机无法备份。在不想增加磁盘的情况下…

【计算机网络】—— 详解码元,传输速率的计算|网络奇缘系列|计算机网络

&#x1f308;个人主页: Aileen_0v0&#x1f525;系列专栏: 一见倾心,再见倾城 --- 计算机网络~&#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 码元 速率和波特 思考1 思考2 思考3 带宽&#xff08;Bandwidth&#xff09; &#x1f4dd;总结 码元…

Linux+Docker+Gitee+Jenkins自动化部署.NET Core服务

目录 一、安装Jenkins 1、跟新yum包 2、查询镜像 3、拉取镜像 4、创建Jenkins工作目录&#xff0c;并将容器内目录挂载到此目录上 5、启动Jenkins容器 二、Jenkins配置 1、Jenkins安装gitee码云插件 2、创建私人令牌 3、Jenkins添加全局凭据 4、系统配置 三、构建任…

C++之程序生成

一、C的发展史 截止到2023年12月&#xff0c;C已经更新了很多版本&#xff0c;并在每个版本中修复了bug和添加了新的特性&#xff0c;ISO C委员会每三年会对C进行一次更新&#xff1a; C98&#xff1a;于1998年发布&#xff0c;是最早的国际标准化版本。它包含了面向对象编程…

Typescript中Omit数据类型的理解

在 TypeScript 中&#xff0c;Omit 是一个内置的工具类型&#xff0c;它用于从对象类型中排除指定的属性&#xff0c;并返回剩余的属性。 Omit 的语法如下所示&#xff1a; type Omit<T, K> Pick<T, Exclude<keyof T, K>>;其中&#xff0c;T 表示原始类型…

D3D12可编程渲染流水线

一、初始化D3D库 启用 DirectX数学库 x86需要启用SSE2指令集&#xff0c;所有平台均需将浮点模型设置为fast。默认为&#xff1a; 精度 (/fp:precise)。 #include <DirectXMath.h> #include <DirectXPackedVector.h> 启用调试模式下的内存泄漏检测 // Enabl…

CCF-CSP真题《202309-5 阻击》思路+ c++满分题解

想查看其他题的真题及题解的同学可以前往查看&#xff1a;CCF-CSP真题附题解大全 试题编号&#xff1a;202309-5试题名称&#xff1a;阻击时间限制&#xff1a;2.0s内存限制&#xff1a;512.0MB问题描述&#xff1a; 问题描述 上回提到&#xff0c;西西艾弗岛下方有一个庞大的遗…

【面试】广告优化

a1&#xff1a;点击率公式是什么&#xff1f;点击率低的原因是什么&#xff1f; 点击率点击/曝光&#xff0c;点击率低的原因主要有两点&#xff1a;一是创意不吸引人&#xff1b;二是目标受众不准确/定向过宽不精确&#xff0c;广告曝光给了对产品不感兴趣用户 a2&#xff1a;…

mysql学习记录

insert into table_nameA(字段名) select 字段名 from table_nameA&#xff08;按照一般的select语句格式进行&#xff09; 通过此语句&#xff0c;可以根据需要抓取数据组成新记录落表 存储过程&#xff1a; 创建&#xff1a; CREATE PROCEDURE pro_name&#xff08; IN o…