【Linux】进程间的通信之共享内存

news2024/11/20 0:32:33

进程间的通信之共享内存

  • 一、system V 内存共享原理
  • 二、共享内存的使用
    • 1、ftok函数
    • 2、shmget函数
    • 3、shmat函数
    • 4、shmdt函数
    • 5、shmctl函数
    • 6、代码使用
  • 三、一些细节的补充

一、system V 内存共享原理

利用内存共享进行进程间的通信的原理其实分为以下几个步骤:

  1. 在物理内存中创建一块共享内存。
  2. 将共享内存链接到要通信的进程的页表中,并通过页表进行进程地址空间的映射。
  3. 进程地址空间映射完毕以后返回首个虚拟地址,以便于进程之间进行通信。

在这里插入图片描述

根据共享内存的原理,一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据,这也就大大的提高了进程间通信的速度。


系统中可以用共享内存进行通信,但是系统中可能不是只有一对进程使用共享内存,在任何一个时刻,可能有多个共享内存在被用来进行通信,所以系统中一定会存在很多共享内存块,操作系统也要整体管理所有的共享内存。

所以共享内存,不是我们想的那样,只要在内存中开辟空间即可,系统也要为了管理共享内存,构建对应的描述共享内存的结构体对象! 在Linux中这个结构体是struct shmid_ds,这个结构体里面存放了共享内存的各种属性。

所以:共享内存 = 共享内存的内核数据结构(struct shmid_ds) + 真正开辟的内存空间

二、共享内存的使用

共享内存的使用涉及很多的系统调用,在这里我们边实现代码边进行讲解。

1、ftok函数

在这里插入图片描述
key_t是一个inttypedef

这个函数的作用就是根据你传递的两个参数,结合函数内部的算法生成一个key_t类型的值,这里我们暂时把这个值记为 key,这个key几乎不可能出现:参数的不同,结果生成相同的key值。

这个key值单独看起来是没有任何作用的,它要与其他的系统调用结合起来才会发挥作用,未来要通信的两个进程就可以在函数ftok输入相同的相同的参数,生成相同的key值,然后通过这个key值就能确定它们想要通信的共享内存是哪一个了。

  • 参数:第一个是路径名,第二个是项目ID(只有最低8位可以使用),我们可以给这两个参数随意赋值,但是这个文件路径必须是现有的,可以访问的的文件,项目ID最低8位必须有效,而且必须非零。

  • 返回值:返回一个key_t类型的值,如果调用失败,返回-1,错误码被设置。

2、shmget函数

在这里插入图片描述
这个函数的作用是:在物理内存中申请一块共享内存,并返回一个和参数key相关联的这块共享内存的标识符。

  • 参数

    1. 第一个参数是用ftok函数生成的key值。

    2. 第二个参数是设置共享内存的大小(你实际得到的大小),但是这个共享内存的大小实际上操作系统是按照PAGE_SIZE(4KB)对齐,来分配的。

    3. 第三个参数是标志位,这里主要介绍三个标志:IPC_CREATIPC_EXCLmode_flags

      IPC_CREAT:如果与key有关共享内存不存在,就创建,如果已经存在就直接返回共享内存的标识符。

      IPC_EXCL: 这个标志要与IPC_CREAT一起使用,表示共享内存如果不存在就创建,如果存在就直接报错,通过这两个标志位的组合,我们能够保证我们拿到的共享内存一定是最新的,而不是以前其他进程可能使用过的。

      mode_flags : 最低9位有效,表示申请的共享内存的权限。

  • 返回值:调用成功,返回一个和参数key相关联的这块共享内存的标识符,调用失败就返回 -1,错误码被设置。

3、shmat函数

在这里插入图片描述

这个函数的作用就是将我们申请得到的共享内存与进程地址空间进行映射,映射完毕以后返回给我们一个映射好以后的首个虚拟地址,通过这个虚拟地址我们就可以进行进程间通信了。

  • 参数

    1. 来自于shmget函数得到的共享内存标识符。
    2. 一个虚拟地址,我们想要将共享内存的地址在进程地址空间的哪里开始映射,如果这里设置为NULL操作系统会自动选择一个合适的地址进行映射。
    3. 标志位,当这里传入SHM_RDONLY时,表示映射以后的进程对于此段空间只有读权限,没有写权限,当我们在这里传入0时,表示读写权限都有。
  • 返回值
    如果函数调用成功就返回映射好以后的首个虚拟地址,以便于进行读取和写入,如果调用失败就会返回一个(void *) -1的值

4、shmdt函数

在这里插入图片描述

当我们在进程地址空间中挂起了一个块共享内存之后当我们不需要使用时,也要将进程地址空间中的链接关系进行取消,shmdt函数的作用就是如此。

  • 参数shmat函数返回的地址。
  • 返回值: 如果调用成功就返回0,调用失败就返回-1

5、shmctl函数

在这里插入图片描述

此函数的功能很强大,里面有许多的标志位,可以完成许多不同的工作,这个函数主要用来控制共享内存。

  • 参数
    1. 来自于shmget函数得到的共享内存标识符。
    2. 是标志位,里面有许多标志,这里我们就介绍两个: IPC_RMIDIPC_STAT

      IPC_RMID: 设置这个标记表示要销毁共享内存,调用者必须是共享内存的创建者,或者是特权用户。

      IPC_STAT: 将shmid相关的内核数据结构中的信息复制到第三个参数buf所指向的shmid_ds结构中,调用者必须要有读权限。
    3. 一个struct shmid_ds类型的指针,在标志位中设置了IPC_STAT,指针所指向的变量里面就能拿到相关的内核信息,如果不关心内核信息可以设置为nullptr
  • 返回值:一般来说,成功返回是0,错误返回结果是-1

6、代码使用

command .hpp

#ifndef __COMMAND_HPP__
#define __COMMAND_HPP__

#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cerrno>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>

#define NUM 4096

const std::string pathname = "./";
const int proj_id = 66;

#endif

sysserve.cpp

#include "command.hpp"

int main()
{
    // 1.生成相同的key值
    key_t key = ftok(pathname.c_str(), proj_id);
    if (key == -1)
    {
        std::cerr << "错误码" << errno << " " << strerror(errno) << std::endl;
        exit(-1);
    }

    // 2.申请共享内存
    umask(0);
    int shmid = shmget(key, NUM, IPC_CREAT | IPC_EXCL | 0666);
    if (shmid == -1)
    {
        std::cerr << "错误码" << errno << " " << strerror(errno) << std::endl;
        exit(-1);
    }

    // 停顿3s观察连接数变为 1
    sleep(2);

    // 3.将共享内存挂接到进程地址空间
    char *s = (char *)shmat(shmid, nullptr, 0);

    // 4.进行进程间的通信
    sleep(6); // 启动另外一个要通信进程,看到连接数变为2

    // 5.取消挂接
    int err = shmdt(s);
    if (err == -1)
    {
        std::cerr << "错误码" << errno << " " << strerror(errno) << std::endl;
    }
    sleep(3);
    
    // 6.删除共享内存
    shmctl(shmid, IPC_RMID, nullptr);

    return 0;
}

sysclient.cpp

#include "command.hpp"

int main()
{
    // 1.生成相同的key值
    key_t key = ftok(pathname.c_str(), proj_id);
    if (key == -1)
    {
        std::cerr << "错误码" << errno << " " << strerror(errno) << std::endl;
        exit(-1);
    }

    // 2.得到共享内存标识符
    int shmid = shmget(key, NUM, IPC_CREAT);
    if (shmid == -1)
    {
        std::cerr << "错误码" << errno << " " << strerror(errno) << std::endl;
        exit(-1);
    }

    // 3.将共享内存挂接到进程地址空间
    char *s = (char *)shmat(shmid, nullptr, 0);

    // 4.进行进程间的通信
    sleep(3);

    // 5.取消挂接
    int err = shmdt(s);
    if (err == -1)
    {
        std::cerr << "错误码" << errno << " " << strerror(errno) << std::endl;
    }

    return 0;
}

Linux的命令行中我们可以使用ipcs -m命令查看共享内存的详细信息。

在这里插入图片描述

可以看到第一个是共享内存的key值,第二个是共享内存的标识符,第三个是拥有者,第四个是权限,第五个是共享内存的字节数,第六个是共享内存的连接数,第七个是共享内存的状态。

运行上面的代码,先启动sysserve再启动sysclient,我们可以看到连接数由0->1 ->2 ->1 ->0 ->被删除

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

三、一些细节的补充

  1. 共享内存的生命周期是随内核的,即进程退出以后如果没有删除共享内存,则共享内存不会消失!
  2. 共享内存没有任何保护机制(同步和互斥)

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

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

相关文章

chatgpt赋能python:Python如何将英文转化为中文的最佳方法

Python如何将英文转化为中文的最佳方法 介绍 在现代全球化社会中&#xff0c;国与国之间的交流越来越频繁&#xff0c;相应的语言翻译工具的需求也愈发迫切。Python是一种易于学习、快速上手的编程语言&#xff0c;适合初学者和经验丰富的程序员使用&#xff0c;在语言翻译方…

技术很牛逼,不会讲PPT,可惜了!

怎样才能做好一场技术分享呢&#xff1f;结合我的经历&#xff0c;做了一些总结。 2015年&#xff0c;我出版《技术管理之巅》以后&#xff0c;先后收到QCon、CSDN、IT168等业界知名技术大会的邀请担任分享嘉宾&#xff0c;几年下来发表了近百场技术及管理相关话题的分享&#…

工业4G路由器 小体积4G LTE通信模块转有线转WiFi充电桩视频安防监控物联网路由器上网CPE

4G LTE代表第四代长期演进&#xff0c;这是一种用于通过蜂窝网络提供高速数据传输的无线通信技术。它是移动网络技术的最新标准&#xff0c;提供比其前身3G更快的数据传输速度。它广泛用于移动设备、物联网设备和机器对机器通信。 近年来&#xff0c;随着物联网技术的快速发展…

探索现代软件架构:揭秘单体、SOA和微服务的进化的之路

1、单体服务、SOA、微服务区别 单体服务 是指一个应用程序中所有的功能都集成在一个单一的代码库中。这种设计模式简单易用&#xff0c;开发人员可以快速地开发和维护应用程序&#xff0c;但是也存在一些问题。例如&#xff0c;当应用程序需要添加新功能时&#xff0c;需要对整…

OpenCV项目开发实战--对图像种的对象进行无缝克隆-附Python、C++的代码实现

文末附基于Python和C++两种方式实现的测试代码下载链接 图 1:无缝克隆示例:一架飞机被克隆到傍晚天空的图片中。 OpenCV 3 中引入的令人兴奋的新功能之一称为无缝克隆。有了这个新功能,您可以从一个图像中复制一个对象,然后将其粘贴到另一个图像中,从而使构图看起来无缝…

FineBI6.0安装部署(最新版)

文章目录 FineBI简介安装步骤场景复现 FineBI简介 FineBI是一款大数据分析的BI工具&#xff0c;同时也是纯B/S架构的商业智能分析服务平台&#xff0c;将其部署到服务器上&#xff0c;就可以通过浏览器进行服务平台的访问和使用。用户在FineBI里面可以进行轻量的数据模型构建&…

Python--常量和变量

Python--常量和变量 <font colorblue>引例<font colorblue>一、常量<font colorblue>二、变量<font colorblue>1.定义<font colorblue>2.变量的赋值<font colorblue>3.变量和变量值的关系<font colorblue>4.标识符、变量名、关键字 …

Golang | Web开发之Gin多服务配置及优雅关闭平滑重启

欢迎关注「全栈工程师修炼指南」公众号 点击 &#x1f447; 下方卡片 即可关注我哟! 设为「星标⭐」每天带你 基础入门 到 进阶实践 再到 放弃学习&#xff01; 专注 企业运维实践、网络安全、系统运维、应用开发、物联网实战、全栈文章 等知识分享 “ 花开堪折直须折&#xf…

大数据基础环境与常用软件搭建

大数据基础环境的搭建需要以下步骤&#xff1a; 安装操作系统&#xff1a;大数据环境通常使用Linux操作系统&#xff0c;推荐使用CentOS或Ubuntu。 安装Java环境&#xff1a;大数据软件通常需要Java环境支持&#xff0c;可以安装OpenJDK或Oracle JDK。 安装Hadoop&#xff1a…

【Android开发基础】多线程-Handle消息机制

文章目录 一、引言二、认识1、为什么要用Handle2、原理图3、关键对象&#xff08;1&#xff09;Message&#xff08;消息类&#xff09;&#xff08;2&#xff09;Handler&#xff08;消息机制&#xff09;&#xff08;3&#xff09;MessageQueue&#xff08;消息处理类&#x…

轻量级报表解决方案Telerik Reporting,轻松完成嵌入式报表交互!

开发者可以通过多种方式与集成在应用程序中的Telerik报表进行交互&#xff0c;从“只是阅读它”到更改报表中包含的数据。 但是要注意&#xff1a;开发者所能做的一些事情将取决于报表是如何创建的&#xff0c;以及它是如何嵌入到应用程序UI中的。因此(和任何应用程序一样)&am…

关于数据库SQL优化

简介 在项目上线初期&#xff0c;业务数据量相对较少&#xff0c;SQL的执行效率对程序运行效率的影响可能不太明显&#xff0c;因此开发和运维人员可能无法判断SQL对程序的运行效率有多大。但随着时间的积累&#xff0c;业务数据量的增多&#xff0c;SQL的执行效率对程序的运行…

假如不干技术,多年学的知识会不会白费?

【1】 有位匿名朋友&#xff0c;在星球中提问&#xff1a; 沈老师&#xff0c;作为一个开发&#xff0c;如果离开了公司&#xff0c;不再做技术&#xff0c;感觉这么多年学的知识都白费了&#xff0c;什么都用不上了&#xff0c;你怎么看&#xff1f; 我的一些思考&#xff0c;…

智能驾考远程监控方案4G工业路由器物联网应用

随着全民经济增长生活水平提高&#xff0c;汽车保有量也随之增长&#xff0c;需要驾驶机动车前提是需要经过标准的驾考培训获得机动车驾驶证后&#xff0c;才能够驾车上路。参加过驾考的朋友们都知道&#xff0c;科目一与科目四都是上机考试&#xff0c;而科目二和科目三则是在…

C#实战:Dapper操作PostgreSQL笔记

目录 一、PostgreSQL简介 二、PostgreSQL组成 三、PostgreSQL的主要优点 四、PostgreSQL的使用场景 五、示例 1、安装dapper&#xff0c;目前本案例安装的版本是1.50.2 2、安装PostgreSQL驱动 3、数据库链接示例 4、通过SQL查询数据列表写法 5、插入示例写法 一、PostgreSQL简介…

Triton教程 -- 快速开始

Triton教程 – 快速开始 文章目录 Triton教程 -- 快速开始创建模型存储库启动 Triton在带 GPU 的系统上运行在纯 CPU 系统上运行验证 Triton 是否正常运行发送推理请求 Triton 推理服务器的新手&#xff0c;想快速部署您的模型吗&#xff1f; 利用这些教程开始您的 Triton 之旅…

FasterTransformer 004 open_attention.h forward

initialize forward() https://github1s.com/NVIDIA/FasterTransformer/blob/v1.0/fastertransformer/cuda/open_attention.h#L149-L217 使用cuBLAS库执行矩阵乘法运算&#xff0c;并对cublasGemmEx&#xff08;&#xff09;进行三个单独的调用。这些操作包括将属性核与输入张…

<Linux开发>驱动开发 -之-内核定时器与中断

&#xff1c;Linux开发&#xff1e;驱动开发 -之-内核定时器与中断 交叉编译环境搭建&#xff1a; &#xff1c;Linux开发&#xff1e; linux开发工具-之-交叉编译环境搭建 uboot移植可参考以下&#xff1a; &#xff1c;Linux开发&#xff1e; -之-系统移植 uboot移植过程详…

Linux系统下安装Kubernetes(超详细。。。)

一、安装Kubernetes前的准备 1.1 准备Hosts文件 &#xff08;注意&#xff0c;请根据Linux虚拟机的IP地址&#xff0c;修改以下命令后再执行&#xff09; cat >>/etc/hosts<<EOF 192.168.100.146 deploy EOF 1.2 检查虚拟机的hostname cat /etc/hostname验证…

Charles抓包配置

这里写目录标题 一、Windows抓包配置1、Help-SSL Proxying-install Charles Root Certificate2、安装并导入证书&#xff0c;按下方各图完成证书导入后&#xff0c;正常情况下&#xff0c;会显示该证书没有问题。3、SSL证书过期解决办法a、可在windows的设置中搜索证书关键字&a…