进程间通信【共享内存】

news2024/9/27 5:51:23

共享内存

    • 共享内存
      • 共享内存原理
      • 创建共享内存
      • 关联共享内存
      • 去关联共享内存
      • 控制共享内存
    • 使用共享内存
    • 代码

共享内存

进程间通信的前提是:先让不同的进程,看到同一份资源

之前,管道进程通信是采用看到同一个文件,那么共享内存就是看到同一份内存

共享内存原理

image-20230106193445842

使用共享内存进行通信

1、先在物理内存中创建共享内存

2、将每一个进程通过页表和共享内存产生关联

3、使用共享内存进行通信

4、使用结束,将进程和共享内存去关联

5、删除共享内存

共享内存,首先需要在物理内存中先创建一份共享内存,通过页表把共享内存映射到各自进程的虚拟进程地址空间的共享区(在栈区和堆区之间(使用动态库时,动态库也映射到这部分))来实现各自进程关联共享内存

ps:有创建共享内存关联共享内存,就有删除共享内存去关联共享内存

创建共享内存

int shmget(key_t key, size_t size, int shmflg);

key:表示共享内存唯一性的值,两个进程使用同一个key值就可以看到同一个共享内存

size:共享内存大小(建议4kb的整数倍)

分配空间单位是4kb,如果申请4097个字节,它会分配给8kb,但是只有4097个字节可供使用

shmflg:IPC_CREAT,IPC_EXCL

PC_CREAT:创建共享内存,如果存在,就获取它,如果不存在,就创建共享内存

IPC_EXCL:不能单独使用,必须和IPC_CREAT组合使用,如果共享内存不存在,就创建共享内存,如果存在,返回失败(这是为了保证函数调用成功一定是一个全新的共享内存)

返回值:如果创建成功,会返回共享内存标识符(shmid),失败会返回-1

在这里我们介绍了shmget函数的参数,那么我们怎么知道这个共享内存是否存在呢?

首先,我们需要知道可能存在多个共享内存,那么就需要对共享内存进行管理,先描述,再组织,那么在内核中,内核会给我们维护共享内存的数据结构。

下表,共享内存的数据结构(ipc_ids

image-20221204195810257

ipc_ids中有一个结构体ipc_id_ary,在ipc_id_ary中有两个字段,size,p,p字段是一个指向kern_ipc_perm数据结构的指针数组

下表,kern_ipc_perm

kern_ipc_perm中有一个keyIPC关键字),通过key来标识共享内存,我们让两个进程使用相同key(key值由用户提供),就可以看到同一个共享内存,进行通信。那么也可以通过key来判断共享内存是否存在

这个key是由用户提供的,就是

int shmget(key_t key, size_t size, int shmflg);

的第一个参数(key_t key),这个key值我们通常使用ftok()函数生成

key_t ftok(const char *pathname, int proj_id);

pathname:一个文件路径

proj_id:一个8位数字,不能为0

返回值为一个密钥(根据文件的inodeproj_id生成)

关联共享内存

void *shmat(int shmid, const void *shmaddr, int shmflg);

将共享内存段连接到进程地址空间

shmid: 共享内存标识符(表示关联到那个共享内存)

shmaddr:指定连接的地址(表示关联到该进程虚拟进程地址空间的哪个位置,一般设为nullptr

shmflg:它的两个可能取值是SHM_RNDSHM_RDONLY(表示对于该共享内存的读写权限,一般设为0,默认读写方式)

返回值:成功返回一个指针,指向共享内存关联到进程地址空间的地址;失败返回-1

去关联共享内存

int shmdt(const void *shmaddr);

将共享内存段与当前进程脱离

shmaddr: 由shmat所返回的指针(共享内存关联到进程地址空间的地址)

返回值:成功返回0;失败返回-1

注意:将共享内存段与当前进程脱离不等于删除共享内存段

控制共享内存

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

用于控制共享内存

shmid:由shmget返回的共享内存标识符

cmd:将要采取的动作(有三个可取值)(IPC_RMID表示立即删除)

buf:指向一个保存着共享内存的模式状态和访问权限的数据结构

返回值:成功返回0;失败返回-1

注意:

当我们运行完毕创建全新的共享内存的代码后(进程退出),再次运行代码,会报错,因为这个共享内存是已存在的。

int main()
{
    key_t key=creat_key();
    cout<<"key:"<<key<<endl;
    //创建共享内存
    int shmid=shmget(key,4096,IPC_CREAT|IPC_EXCL);
    if(shmid<0)
    {
        log()<<"error"<<strerror(errno)<<endl;
        exit(2);
    }
    log()<<"shared memory: sucessed"<<endl;
    return 0;
}

system V下的共享内存,生命周期是随内核的,如果不显示删除,就必须重启os解决.

image-20221208100243302

如何显示删除

  • 命令行

    ipcrm -m shmid
    

    image-20221208100331885

  • 系统接口

    int shmctl(int shmid, int cmd, struct shmid_ds *buf);
    

如何查看IPC资源

ipcs -m

image-20221208100313035

perms:表示该共享内存的读写权限(当前perms为0,那就无法对共享内存进行读写,所以创建共享内存时需要*|读写权限*)

nattch:表示挂接到该共享内存的进程数

使用共享内存

我们把共享内存和进程产生关联,是把共享内存通过页表映射到进程地址空间的栈区和堆区之间的共享区,也就是映射到用户空间,既然是用户空间,那么我们就可以直接进行使用,而不需要调用系统接口。

同时因为共享内存被关联到进程的用户空间,可以被进程直接使用,这使得共享内存是进程间通信最快的方式,同时导致共享内存没有任何访问控制机制,不会发生阻塞等待,共享内存可以直接通信,但不安全

代码

两个进程使用共享内存进行通信

comm.hpp

#pragma once

#include<iostream>
#include<map>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<cstring>
#include<sys/types.h>
#include<unistd.h>
#include<time.h>

#define IPC_PATH "/home/byld/test_linux"

//创建key值,两个进程使用相同的key值访问相同的共享内存
key_t creat_key()
{
    return ftok(IPC_PATH,0X12);
}

std::ostream& log()
{
   std::cout<<"时间戳"<<time(nullptr)<<"|";
   return std::cout;
}

client_IPC.cpp

#include"comm.hpp"

using namespace std;

int main()
{
    key_t key=creat_key();
    //获取共享内存
    int shmid=shmget(key,4096,IPC_CREAT);
    //关联到进程
    char* str=(char*)shmat(shmid,nullptr,0);
    if(str==(char*)-1)
    {
        log()<<"attach failed"<<endl;
        exit(3);
    }
    log()<<"attach successed"<<endl;

    //使用
    //写入
    while(1)
    {
        cout<<"客户端:输入#:"<<endl;
        ssize_t s = read(0,str,4096);
        if(s>0)
        {
            str[s]='\0';
        }
    }


    //去关联
    shmdt(str);
    log()<<"detach sucess"<<endl;

    return 0;
}

server_IPC.cpp

#include"comm.hpp"

using namespace std;

int main()
{
    key_t key=creat_key();
    cout<<"key:"<<key<<endl;
    //创建共享内存
    int shmid=shmget(key,4096,IPC_CREAT|IPC_EXCL|0666);
    if(shmid<0)
    {
        log()<<"error"<<strerror(errno)<<endl;
        exit(2);
    }
    log()<<"shared memory sucessed shmid:"<<shmid<<endl;
    //进程关联共享内存
    char* str=(char*)shmat(shmid,nullptr,0);
    if(str==(char*)-1)
    {
        log()<<"attach failed"<<endl;
        exit(3);
    }
    log()<<"attach successed shmid:"<<shmid<<endl;

    //使用
    //读出
    while(1)
    {
        cout<<"服务器端读出#:";
        cout<<str<<endl;
        sleep(1);
    }
    //进程去关联共享内存
    shmdt(str);
    log()<<"detach sucess"<<endl;
    //删除共享内存
    shmctl(shmid,IPC_RMID,nullptr);
    return 0;
}

动画

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

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

相关文章

审查 Git 仓库的绝佳工具Tig

简介 Tig 是一个 基于 ncurses 的 Git 文本模式界面&#xff0c;它允许你浏览 Git 仓库中的更改。它还可以充当各种 Git 命令输出的分页器。使用这个工具可以让我很好地了解在哪个提交中发生了哪些更改&#xff0c;最新的提交合并是什么等等。 git工作原理&#xff1a;https:…

黑马学ElasticSearch(三)

目录&#xff1a; &#xff08;1&#xff09;RestClient-操作索引库-导入demo &#xff08;2&#xff09;RestClient操作索引-hotel数据结构分析 &#xff08;3&#xff09;RestClient操作索引库-初始化RestClient &#xff08;4&#xff09;RestClient操作索引库-创建索引库…

如何掌握TikTok广告投放技巧,玩转“TikTok+独立站”新模式?

导读&#xff1a;TikTok已经发展成为全球第六大社交媒体网络&#xff0c;这使其成为一个非常富饶的广告目的地。 跨境卖家如何在 TikTok 上投放广告&#xff1f;在“TikTok独立站”模式中&#xff0c;卖家在 TikTok ads 上投放电商广告&#xff0c;用户点击后将跳转到独立站落地…

21. 合并两个有序链表(链表)

文章目录题目方法一 暴力法:创建头结点,比较拼接方法二 递归法参考文献题目 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,…

【从零开始学习深度学习】42. 算法优化之AdaDelta算法【基于AdaGrad算法的改进】介绍及其Pytorch实现

除了上一篇文章介绍的RMSProp算法以外&#xff0c;另一个常用优化算法AdaDelta算法也针对AdaGrad算法在迭代后期可能较难找到有用解的问题做了改进 。比较有意思的是&#xff0c;AdaDelta算法没有学习率这一超参数。 目录1. AdaDelta算法介绍2. 从零实现AdaDelta算法3. Pytorch…

UDS诊断系列介绍04-10会话服务

本文框架1. 系列介绍10服务概述2. 10服务请求与应答2.1 10服务请求2.2 肯定应答2.3 否定应答1. 系列介绍 UDS&#xff08;Unified Diagnostic Services&#xff09;协议&#xff0c;即统一的诊断服务&#xff0c;是面向整车所有ECU的一种诊断通信方式&#xff0c;是基于ISO 14…

Linux学习笔记——集群化环境前置准备

5.7、集群化环境前置准备 5.7.1、介绍 在前面&#xff0c;我们所学习安装的软件&#xff0c;都是以单机模式运行的。 后续&#xff0c;我们将要学习大数据相关的软件部署&#xff0c;所以后续我们所安装的软件服务&#xff0c;大多数都是以集群化&#xff08;多台服务器共同…

使用OpenCV读取视频、图片并做简单处理

1.OpenCV的安装与卸载 在conda中安装opencv&#xff0c;打开Anaconda Prompt 使用国内镜像源安装opencv&#xff0c;命令如下&#xff1a; pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple 也可以安装opencv的另一个扩展包opencv-contrib-python&am…

Centos下使用yum安装Mysql8(Mysql5.7)以及常见的配置和使用

记录一下在centos7.x下面使用yum方式安装mysql8(Mysql5.7)关系型数据库安装之前一般需要先确定centos7.x服务器里是否已经安装&#xff0c;未安装或者刚初始化的centos7.x服务器最好安装&#xff0c;原来已经有的要升级的话一定要对系统原有mysql 或mariadb卸载干净&#xff0c…

系统测试的具体测试类型

系统测试&#xff1a;是为判断系统是否符合要求而对集成的软、硬件系统进行的测试活动、它是将已经集成好的软件系统&#xff0c;作为基于整个计算机系统的一个元素&#xff0c;与计算机硬件、外设、某些支持软件、人员、数据等其他系统元素结合在一起&#xff0c;在实际运行环…

Charles - 夜神模拟器证书安装App抓包

Charles - 夜神模拟器证书安装App抓包 文章目录Charles - 夜神模拟器证书安装App抓包前言一、软件安装1.Openssl安装1.1下载安装1.2配置环境变量1.3查看openssl版本&#xff0c;输入命令&#xff1a;openssl version2.夜神模拟器安装1.1 下载安装1.2工具准备&#xff0c;MT管理…

【Lilishop商城】No4-6.业务逻辑的代码开发,涉及到:接口入参、出参开发逻辑,及POJO的各种总结

仅涉及后端&#xff0c;全部目录看顶部专栏&#xff0c;代码、文档、接口路径在&#xff1a; 【Lilishop商城】记录一下B2B2C商城系统学习笔记~_清晨敲代码的博客-CSDN博客 全篇会结合业务介绍重点设计逻辑&#xff0c;其中重点包括接口类、业务类&#xff0c;具体的结合源代…

完整iOS APP发布App Store上架流程指南

本文章的目的在于教会你如何创建ios的打包证书和如何上架假如你没有任何的打包或上架经验&#xff0c;参考本文有很大的收益。通常创建ios证书和上架&#xff0c;是需要MAC电脑的&#xff0c;本文重点介绍如何在没有mac电脑的情况下&#xff0c;创建mac证书和上架。假如你还没有…

STM32CUBEIDE-简单案例生成

STM32CUBEIDE-简单案例生成 京东链接&#xff1a;https://i-item.jd.com/66584659856.html 生成工程 使用STM32CUBEMX生成例程&#xff0c;这里使用STM32F103C8T6系统板。 新建一个工程&#xff0c;这里有3种新建工程方式。 ● 基于MCU/MPU新建工程 ● 基于ST模块新建工程 ●…

PCB板缺陷检测机器视觉识别算法 yolo

PCB板缺陷检测机器视觉识别算法通过pythonyolo系列网络深度学习模型对PCB电路板外观实时监测&#xff0c;当模型算法监测到有缺陷的PCB板时立即抓拍存档。Python是一种由Guido van Rossum开发的通用编程语言&#xff0c;它很快就变得非常流行&#xff0c;主要是因为它的简单性和…

Vue2进阶笔记

Vue2进阶笔记一、基础知识1.1 computed计算属性1.2 watch监视属性1.3 动态绑定样式1.4 列表循环渲染 key的探讨1.5 列表过滤1.6 数据监视1.7 表单收集1.8 过滤器1.9 生命周期函数1.10 nextTick1.11 动画与过渡1.12 脚手架配置跨域代理二、组件化开发2.1 演替与定义2.2 使用与注…

多线程进阶(一)锁策略,CAS及Synchronized原理

目录 前言&#xff1a; 常见锁策略 CAS CAS应用场景 标准库中基于CAS实现的原子类介绍 代码实现 ABA问题 Synchronized原理 锁升级 锁消除 锁粗化 小结&#xff1a; 前言&#xff1a; 通过这篇文章可以更加深入理解锁内部的一些实现原理&#xff0c;以及怎样描述一…

Qt 使用 Matlab函数

背景&#xff1a;个人的Qt项目中&#xff0c;需要一个图片分割算法。该算法之前在Matlab上实现过&#xff0c;同时转成C版本有点麻烦&#xff0c;因此尝试通过Qt与Matlab编程相结合的方式&#xff0c;实现该功能。 注意&#xff1a;以下所有功能及配置过程&#xff0c;默认已经…

CSDN竞赛21期题解

总结 &#xff08;PS&#xff1a;这次竞赛的奖励对我诱惑力感觉没多大&#xff0c;因为高级背包不久前才收到一个&#xff0c;邹老师的两本签名书也早就拿到了&#xff0c;程序员杂志、帆布包也都有了&#xff0c;扑克牌都拿了几副了&#xff0c;所以还是换点其他的书比较好&a…

c语言tips-【c语言内存模型】

0.摘要 C语言是比较接近底层的语言&#xff0c;因此它的很多知识点是和操作系统挂钩的&#xff0c;例如它的内存模型&#xff0c;其实也是操作系统进程的内存模型&#xff0c;本文章就是解释进程&#xff0c;虚拟内存空间&#xff0c;内存模型的相关知识和它们之间的联系 1. 虚…