Linux-共享内存

文章目录

  • 前言
  • 一、system V共享内存
      • 申请共享内存
      • 挂载共享内存
      • 删除共享内存挂载
      • 删除共享内存
  • 二、示例代码
  • 三.运行效果


前言


在这之前我们已经学习了两种进程间通信方式:匿名管道和命名管道。
从我们之前的学习已经知道,想让多个进程间进行通信就需要让他们一起看到同一份资源。
匿名管道是通过fork子进程来让子进程继承父进程的fd。
命名管道是通过生成命名管道文件,并一起打开管道文件。

一、system V共享内存

共享内存相对于我们之前的管道通信有一定区别:

1.共享内存是要让多个进程看到同一份内存.

根据之前我们介绍过的冯洛伊曼体系,对于内存级别的通信特性就代表了共享内存其通信效率要高于管道通信!

2.进程想要看到同一份共享内存,需要key

在这里插入图片描述
这里生成的key方式与哈希字符串类似,通过算法来形成key。所以要想要形成同样的key,就必须确保pathname和porj_id相同,不同进程凭借同样的key来访问同一份共享内存!

申请共享内存

在这里插入图片描述
参数key 代表如果要访问该共享内存需要的key。
参数size代表申请的共享内存大小,这里需要注意的是,共享内存的大小是以4096个字节为单位,所以size最好是4096的倍数。
参数shmflg是模式选项,有 IPC_CREAT 和 IPC_EXCL , IPC_CREAT单独使用代表 如果没有该共享内存则创建,有则使用已经存在的。 IPC_EXCL单独使用没有意义,如果和IPC_CREAT一起使用代表如果没有该共享内存则创建,如果已经存在则报错。
返回值是共享内存的id,就跟文件一样,我们的共享内存也需要进行管理,所以就也有id。

挂载共享内存

由于我们的共享内存的通信方式是让多个进程看到同一份内存,从我们之前学习地址空间的知识,进程需要通过虚拟地址空间->页表->物理内存,所以,要想看到看到位于物理内存的共享内存,就需要修改页表来做到,所以提供了挂载共享内存的接口函数
在这里插入图片描述
参数shmid是我们刚刚讲的共享内存id。
参数shmaddr 可以指定shmaddr的地址为挂载的共享内存地址,一般设置为nullptr。
参数shmflg是模式选项,SHM_RND和SHM_RDONLY,SHM_RND与shmaddr相关,SHM_RDONLY指定该进程只允许对共享内存进行读操作。
返回值为挂载的共享内存地址。

删除共享内存挂载

注意:这里是删除挂载,不是删除共享内存!!!

在这里插入图片描述
参数shmaddr为共享内存在该进程的地址。
返回值若为1则删除成功,-1则发生错误。

删除共享内存

在这里插入图片描述
参数shmid为共享内存id。
参数cmd为模式选项,其中IPC_RMID为删除选项
参数buf这里暂时不讨论。
返回值若为1则删除成功,-1则发生错误

我们要想删除共享内存也不止这一种方式

通过输入ipcs -m 查看存在的共享内存属性
在这里插入图片描述

通过输入ipcrm -m shmid 来删除共享内存

二、示例代码

#Server端
#include "comm.hpp"
#include "Log.hpp"int main()
{// 1.创建创建tokenkey_t key = ftok(PATH_NAME, PROJ_ID);Log(Debug) << "共享秘钥创建成功! step 1"<< " [key:" << getKey(key) << "]" << std::endl;// 2.申请共享内存int shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666);if (shmid == -1){Log(Error) << "共享内存创建失败!!!!! step 2" << std::endl;perror("shmget");exit(1);}Log(Debug) << "共享内存创建成功! step 2" << std::endl;//sleep(10);char *shmaddr = (char *)shmat(shmid, nullptr, SHM_RDONLY);if ((void *)shmaddr == (void *)-1){Log(Error) << "共享内存挂载失败!!!!!! step 3" << std::endl;perror("shmat");exit(2);}Log(Debug) << "共享内存挂载成功! step 3" << std::endl;// sleep(5);//开始访问共享内存while(1){printf("%s\n",shmaddr);sleep(1);if(strcmp(shmaddr,"quit") == 0) break;}int n = shmdt(shmaddr);if (n == -1){Log(Error) << "共享内存挂载删除失败! step 4" << std::endl;perror("shmdt");exit(3);}Log(Debug) << "共享内存挂载删除! step 4" << std::endl;//sleep(5);n = shmctl(shmid, IPC_RMID, nullptr);if (n == -1){Log(Error) << "共享内存删除失败! step 5" << std::endl;perror("shmctl");exit(4);}Log(Debug) << "共享内存删除成功! step 5" << std::endl;return 0;
}
#Client端
#include "Log.hpp"
#include "comm.hpp"int main()
{key_t key = ftok(PATH_NAME, PROJ_ID);Log(Debug) << "共享秘钥创建成功!step 1"<< " [key:" << getKey(key) << "]" << std::endl;int shmid = shmget(key, SHM_SIZE, 0);if (shmid == -1){Log(Error) << "共享内存获取失败!!!!! step 2" << std::endl;perror("shmget");exit(1);}Log(Debug) << "共享内存获取成功!step 2" << std::endl;//sleep(10);char *shmaddr = (char *)shmat(shmid, nullptr, 0);if ((void *)shmaddr == (void *)-1){Log(Error) << "共享内存挂载失败!!!!!! step 3" << std::endl;   perror("shmat");exit(2);}Log(Debug) << "共享内存挂载成功!step 3" << std::endl;//sleep(5);while(1){//std::cout << "请输入:->" ;ssize_t n = read(0, shmaddr, SHM_SIZE - 1);if(n > 0){shmaddr[n - 1] = 0;if(strcmp(shmaddr,"quit") == 0) break;}}int n = shmdt(shmaddr);if (n == -1){Log(Error) << "共享内存挂载删除失败! step 4" << std::endl;perror("shmdt");exit(3);}Log(Debug) << "共享内存挂载删除!step 4" << std::endl;//sleep(5);return 0;
}
comm.hpp
#include <iostream>
#include <cstdio>
#include <sys/types.h>
#include <sys/ipc.h>
#include <assert.h>
#include <sys/shm.h>
#include <unistd.h>
#include <cstring>
#define PROJ_ID 10086
#define SHM_SIZE 4096char buffer[514] = {0};const char *getKey(key_t key)
{sprintf(buffer, "0x%x", key);return buffer;
}#define PATH_NAME "/home/fengjunzi/test"
Log.hpp
#include <iostream>
#include <time.h>
#include <string>#define Debug 0
#define Error 1const std::string com[] = {"Debug","Error"};std::ostream &Log(int command)
{std::cout << "[" << (unsigned)time(nullptr) << "]:"<< "[" << com[command] << "]" <" ";return std::cout;
}

三.运行效果

在这里插入图片描述
它的缺陷从运行就可以看出来,共享内存没有进行同步与互斥。
不能像管道一样具有访问控制,就会出现写端只写了一半,但是读端已经开始读了的情况。

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

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

相关文章

【多线程】ThreadLocal 详解,举例说明

ThreadLocal 是 Java 中的一个线程级别的变量&#xff0c;用于在多线程环境下保持变量的独立性。每个线程都可以独立地设置和获取 ThreadLocal 的值&#xff0c;而不会影响其他线程。通常情况下&#xff0c;ThreadLocal 被用来在方法或类之间传递变量。 1、原理&#xff1a; …

java数据结构与算法刷题-----LeetCode667. 优美的排列 II

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 解题思路 题目要求我们返回一个数组长度为n的数组&#xff0c;必须含有1~n…

C语言通过IXMLHTTPRequest以get或post方式发送http请求获取服务器文本或xml数据

做过网页设计的人应该都知道ajax。 Ajax即Asynchronous Javascript And XML&#xff08;异步的JavaScript和XML&#xff09;。使用Ajax的最大优点&#xff0c;就是能在不更新整个页面的前提下维护数据。这使得Web应用程序更为迅捷地回应用户动作&#xff0c;并避免了在网络上发…

JS进阶-深入对象(二)

拓展&#xff1a;深入对象主要介绍的是Js的构造函数&#xff0c;实例成员&#xff0c;静态成员&#xff0c;其中构造函数和Java种的构造函数用法相似&#xff0c;思想是一样的&#xff0c;但静态成员和实例成员和java种的有比较大的差别&#xff0c;需要认真理解 • 创建对象三…

el-select选择之后值不显示在文本框的问题解决

问题场景如下图&#xff1a; 在el-collapse-item中使用子组件&#xff0c;子组件里是el-form-item代码。el-select在for循环中&#xff0c;可以有多个。 查了一下博客&#xff0c;有的说这种场景需要给el-select添加change事件&#xff0c;加上 this.$forceUpdate() 强制刷新即…

【单例模式】保证线程安全实现单例模式

&#x1f4c4;前言&#xff1a;本文是对经典设计模式之一——单例模式的介绍并讨论单例模式的具体实现方法。 文章目录 一. 什么是单例模式二. 实现单例模式1. 饿汉式2. 懒汉式2.1 懒汉式实现单例模式的优化&#xff08;一&#xff09;2.2 懒汉式实现单例模式的优化&#xff08…

仿真机器人-深度学习CV和激光雷达感知(项目2)day04【简单例程】

文章目录 前言简单例程运行小海龟仿真启动节点查看计算图发布 Topic调用 Serviece 用 Python 发布和接收 Topic创建工作空间创建功能包&#xff0c;编译编写 Topic Publisher 节点编写 Topic Subscriber 节点运行节点 自定义消息类型用 Python 注册和调用 Serviece新建功能包在…

【若依】关于对象查询list返回,进行业务处理以后的分页问题

1、查询对象Jglkq返回 list&#xff0c;对 list 进行业务处理后返回&#xff0c;但分页出现问题。 /*** 嫁功率考勤查询*/RequiresPermissions("hr:kq:list")PostMapping("/list")ResponseBodypublic TableDataInfo list(Jglkq jglkq) throws ParseExcepti…

Spring基于dynamic-datasource实现MySQL多数据源

目录 多数据源实现 引入依赖 yml配置文件 业务代码 案例演示 多数据源实现 引入依赖 <dependency><groupId>com.baomidou</groupId><artifactId>dynamicdatasourcespringbootstarter</artifactId><version>3.5.0</version> &…

[Python] glob内置模块介绍和使用场景(案例)

Unix glob是一种用于匹配文件路径的模式&#xff0c;它可以帮助我们快速地找到符合特定规则的文件。在本文中&#xff0c;我们将介绍glob的基本概念、使用方法以及一些实际应用案例。 glob介绍 Glob(Global Match)是Unix和类Unix系统中的一种文件名扩展功能&#xff0c;它可以…

【python文件】生成的csv文件没两行数据之间有一个空行

问题描述 用python代码将数据写入csv文件&#xff0c;但生成的csv文件没两行数据之间有一个空行&#xff0c;如下图所示&#xff1a; 解决办法 在open函数中添加newline&#xff0c;如以下代码所示&#xff0c;即可解决这一问题。 with open(r"C:\Users\xxx\Desktop\DR…

未来已来:AI引领智能时代的多领域巨变

大家好&#xff0c;今天我们将深入探讨人工智能如何彻底改变我们的生活方式&#xff0c;领略未来的无限可能性。 1. 医疗革新&#xff1a;AI担任超级医生 医疗领域是AI最引人注目的战场之一。智能医学影像诊断系统&#xff0c;不仅能够精准识别病变&#xff0c;还能辅助医生提…