Linux 中System V IPC的共享内存

news2024/11/17 0:38:20

1. 概念介绍

System V IPC(Inter-Process Communication)是一组在UNIX系统中用于进程间通信的机制,包括共享内存、消息队列和信号量。这些机制由System V内核提供,并且它们的存在不依赖于创建它们的进程,而是由内核管理,直到显式删除。由于消息队列和信号量并不常用,故而以下主要介绍共享内存。

2. 共享内存 shm

共享内存允许不同进程共享一段由操作系统亲自开辟的物理内存,进程可以通过读写这段内存来交换数据。共享内存是最快的IPC方式,因为它减少了复制数据的需要,如通过管道交换数据时需要经过从内存复制到缓冲区中。

基本原理如上图,共享内存会被进程的页表直接映射到自己的进程地址空间的共享区,从而通过进程地址空间直接对内存进行操作,实现资源的共享与交换。

共享内存函数

shmget函数

功能:用来创建共享内存
返回值:成功返回一个非负整数,即该共享内存段的标识码 shmid ;失败返回 -1

参数:

  • key: 一个整数键值,用于唯一标识共享内存段,以创建或获取

我们可以看到 key 的类型为 key_t,实际上也是一个整数,不过要保证其数值的唯一性,要获取该参数 key 我们需要使用 ftok 函数,它会根据一个文件路径和一个项目标识符(proj_id)通过一系列算法生成一个几乎唯一的键值。

  • pathname 是一个指向存在的文件路径的指针,实际上可以随便写。
  • proj_id 是一个整数,通常是一个字符常量,其低8位被用于生成键值,实际上可以随便写。

key 是System V的唯一标识符,注意不是shm的,shmid 是 shm 的唯一标识符。

  • size: 共享内存大小,以字节为单位

注意:共享内存以4 kb为基本单位开辟内存,也就是4096 byte,哪怕只申请了1 byte的内存,实际上还是会开辟4096 byte大小的空间。因此开辟shm的时候,这个参数最好设置为4096的倍数。

  • shmflg: 由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的。

其中最为常用的shmflg如下:

  • IPC_CREAT:如果共享内存段不存在,则创建一个新的共享内存段,存在则返回 shmid。
  • IPC_EXCL:与IPC_CREAT一起使用时,确保创建新的共享内存段,如果共享内存段已存在则失败。
  • 权限位:shmflg的低9位用于设置共享内存段的权限,与文件系统的权限位相同。
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
int main()
{
    key_t key=ftok("/home/lbk/lesson17/test.cpp",8888);
    int shmid=shmget(key,4096,IPC_CREAT|IPC_EXCL|0666);
    return 0;
}

第一个参数 key:我们通过ftok获得该唯一的共享内存的system V标识符key;
第二个参数为4096:即开辟的共享内存大小为4096 byte;
第三个参数为IPC_CREAT | IPC_EXCL | 0666:如果当前的key不存在,则创建对应的共享内存,该共享内存的初始权限为0666,如果存在,则创建失败。

通过 ipcs指令可以看当前所有的system V的总体情况:

也可以通过 ipcs -m命令只看共享内存的情况:

前面我们已经提到共享内存的存在不依赖于创建它们的进程,而是由内核管理,直到显式删除。即进程已经结束了,但是进程创建的共享内存还存在,如果想要删除一个共享内存,我们可以通过ipcrm -m shmid 命令。

shmat函数

共享内存是被直接映射到进程地址空间的共享区的,进程可以通过访问进程地址空间来访问共享内存,而从内存映射到进程地址空间我们就需要shmat函数。

功能:将共享内存段连接到进程地址空间
返回值:成功返回一个指针,指向共享内存第一个节;失败返回 -1
参数
  • shmid: 由 shmget 函数返回的共享内存段的标识符。
  • shmaddr: 一个指向进程地址空间中的位置的指针,用于指定共享内存段附加的起始地址。通常,这个参数设置为 NULL,让系统自动选择一个合适的地址。
  • shmflg: 一个标志位,可以包含 SHM_RDONLY 来指定以只读方式附加共享内存,或者 0 以允许读写。

shmdt函数

当一个进程不再需要访问共享内存时,可以调用 shmdt 来解除共享内存与该进程地址空间的关联。这个函数不会删除共享内存,只是使其对当前进程不可用。

功能:将共享内存段与当前进程脱离
返回值:成功返回 0 ;失败返回 -1
参数:
shmaddr: shmat 所返回的指针

shmctl函数

功能:用于控制System V共享内存段的系统调用。它可以执行多种操作,包括获取共享内存段的状态信息、修改共享内存段的属性、以及删除共享内存段。
返回值:成功返回 0 ;失败返回 -1
参数:
  • shmid: shmget返回的共享内存标识码
  • cmd: 命令参数,指定了要对共享内存段执行的操作(有三个可取值)

IPC_STAT:获取共享内存段的状态信息
IPC_SET:设置共享内存段的某些属性
IPC_RMID:删除共享内存段

  • buf: 一个指向 shmid_ds 结构的指针,用于存储或接收共享内存段的信息。如果 cmd 是IPC_STAT 或 IPC_SET, 则 buf 不为 NULL;如果 cmd 是 IPC_RMID,则 buf 可以为 NULL

shmid_ds 结构体是与System V共享内存段相关联的数据结构,它包含了共享内存段的各种状态信息和属性。这个结构体在 <sys/shm.h> 头文件中定义,并且在内核中用于维护每个共享内存段的信息。

struct shmid_ds {
    struct ipc_perm shm_perm;    /* Ownership and permissions */
    size_t          shm_segsz;   /* Size of segment (bytes) */
    time_t          shm_atime;   /* Last attach time */
    time_t          shm_dtime;   /* Last detach time */
    time_t          shm_ctime;   /* Last change time */
    pid_t           shm_cpid;    /* PID of creator */
    pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
    shmatt_t        shm_nattch;  /* No. of current attaches */
    ...
};
使用示例:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <iostream>
using namespace std;
int main()
{
    key_t key = ftok("/home/lbk/lesson17/test.cpp", 8888);
    int shmid = shmget(key, 4096, IPC_CREAT | IPC_EXCL | 0666);
    if (shmid == -1)
    {
        perror("shmget");
        exit(-1);
    }
    struct shmid_ds shm;
    shmctl(shmid, IPC_STAT, &shm);
    cout << "shm_nattch:" << shm.shm_nattch << endl;
    cout << "shm_segsz:" << shm.shm_segsz << endl;
    shmctl(shmid, IPC_RMID, NULL);
    return 0;
}

进程间通信示例

comm.hpp

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <iostream>
using namespace std;

#define PATH_NAME "/home/lbk/lesson17/comm.hpp"
#define PROJECT_ID 0x8888
#define SHM_SIZE 4096
key_t Getkey()
{
    return ftok(PATH_NAME, PROJECT_ID);
}
int Creatshm()
{
    int shmid = shmget(Getkey(), SHM_SIZE, IPC_CREAT | IPC_EXCL | 0666);
    if (shmid == -1)
    {
        cout << "shmget error" << endl;
        return -1;
    }
    return shmid;
}
int Getshm()
{
    int shmid = shmget(Getkey(), SHM_SIZE, IPC_CREAT);
    if (shmid == -1)
    {
        cout << "shmget error" << endl;
        return -1;
    }
    return shmid;
}

server.cpp

#include "comm.hpp"
int main()
{
    int shmid = Creatshm();
    char *buf = (char *)shmat(shmid, NULL, 0);
    cout << "Client start" << endl;
    while (true)
    {
        cout << "Please Enter@";
        cin >> buf;
    }
    shmctl(shmid, IPC_RMID, NULL);
    return 0;
}

client.cpp

#include "comm.hpp"
int main()
{
    int shmid = Getshm();
    char *buf = (char *)shmat(shmid, NULL, 0);
    while (true)
    {
        cout << "client receive:" << buf << endl;
        sleep(1);
    }
    return 0;
}

makefile

.PHONY:all
all:client.exe server.exe
client.exe:client.cpp
	g++ -o $@ $^
server.exe:server.cpp
	g++ -o $@ $^
.PHONY:clean
clean:
	rm -f client.exe server.exe

特点

  • 高效性:共享内存允许直接在内存中交换数据,避免了数据拷贝的开销,因此在进程间通信中速度非常快。

  • 同步问题:由于多个进程可以同时访问共享内存,因此需要同步机制来避免数据竞争和一致性问题。通常,进程会使用信号量或互斥锁来同步对共享内存的访问。

  • 系统资源:共享内存不需要操作系统维护额外的通信队列或管道,它直接使用进程的地址空间。

在使用共享内存时,需要注意的是,共享内存的内容在系统重启后不会持久化,因为它存储在物理内存中,而不是磁盘上。此外,共享内存的管理通常涉及一系列系统调用,如 shmget 创建共享内存段,shmat 将共享内存段附加到进程的地址空间,shmdt 分离共享内存段,以及 shmctl 控制共享内存段的属性和状态.

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

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

相关文章

JSON数组

数组作为JSON对象 ["Google","Runoob","Taobao"] JSON数组在中括号中书写。 中括号[]保存的数组是值&#xff08;value&#xff09;的有序集合。一个数组以左中括号[开始&#xff0c;右中括号]结束&#xff0c;值之间使用逗号&#xff0c;分隔…

【第28章】Spring Cloud之Sentinel注解支持

文章目录 前言一、注解埋点支持二、SentinelResource 注解三、实战1. 准备2. 纯资源定义3. 添加资源配置 四、熔断(fallback)1. 业务代码1.1 Controller1.2 Service1.3 ServiceImpl 2. 熔断配置3. 熔断测试 总结 前言 上一章我们已经完成了对Sentinel的适配工作&#xff0c;这…

物联网架构

1 三层架构 三层架构就像我们拿着一个设备&#xff0c;通过网络直接连接到服务器获取结果&#xff0c;步骤简单。 举个例子&#xff1a;智能家居的温度监控系统 1. 感知层&#xff08;设备与传感器&#xff09; 在智能家居系统中&#xff0c;温度传感器被安装在家里的各个房间…

数据结构C //线性表(顺序表)ADT结构及相关函数

数据结构&#xff08;C语言版&#xff09;严蔚敏 吴伟民 线性表&#xff08;顺序表&#xff09;ADT结构及相关函数 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;vim 代码块&#xff08;头文件&#xff0c;函数文件&#xff0c;主文件&am…

JVM字节码与局部变量表

文章目录 局部变量表javap字节码指令分类 指令指令数据类型前缀加载和存储指令加载常量算术指令其他指令 字节码示例说明 局部变量表 每个线程的帧栈是独立的&#xff0c;每个线程中的方法调用会产生栈帧&#xff0c;栈帧中保存着方法执行的信息&#xff0c;例如局部变量表。 …

Alinx MPSoC驱动开发第11章异步IO实验按下按键报IO Possibile后结束进程

实验现象 使用Alinux官方提供的驱动和应用程序代码&#xff0c;petalinux工程基于自身需要进行了一定的修改&#xff08;主要是SD卡根文件系统&#xff09;。在把petalinux工程编译后打包的boot.scr、BOOT.BIN、image.ub放入FAT分区&#xff0c;把驱动程序与应用程序放在NFS共享…

万界星空科技电池MES具体功能及解决方案

电池的生产工艺具有高度的复杂性和精细度。从原材料的准备、电池的组装到最终的测试与包装&#xff0c;每一道工序都需要严格控制&#xff0c;以确保产品的质量和性能。 万界星空科技在电池MES&#xff08;制造执行系统&#xff09;领域提供了全面的解决方案&#xff0c;这些解…

JavaWeb项目打包、部署至Tomcat并启动的全程指南(图文详解)

前言 我们想要部署一个javaWeb项目到tomcat上&#xff0c;需要了解一些概念 什么是tomcat&#xff1f; Tomcat 是 Apache 软件基金会&#xff08;Apache Software Foundation&#xff09;下的一个开源项目&#xff0c;主要用于实现 Java Servlet、JavaServer Pages&#xff08;…

在 PyCharm 中配置 Anaconda 环境

1. 安装 Anaconda 如果尚未安装 Anaconda&#xff0c;你可以从 Anaconda 官方网站 下载或者从清华镜像网站下载并安装适合你操作系统的版本。 2. 创建 Anaconda 虚拟环境 打开 Anaconda Prompt&#xff08;Windows&#xff09;或终端&#xff08;macOS/Linux&#xff09;。 …

EmguCV学习笔记 VB.Net 11.6 图像分割

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…

如何升级用 Helm 安装的极狐GitLab Runner?

本分分享如何对 Helm 安装的 Runner 进行升级。整个过程分为三步&#xff1a;1、确定 Runner 最新版本或者想要升级的版本是否存在&#xff1b;2、用 Helm upgrade 命令进行升级&#xff1b;3、升级确认。 极狐GitLab 为 GitLab 的中国发行版&#xff0c;中文版本对中国用户更…

【西电电装实习】6. 手装无人机的蓝牙断连debug

文章目录 前言零、闪灯状态零零、翻滚角&#xff0c;俯仰角&#xff0c;偏航角一、问题描述二、现象解释三、解决方案参考文献 前言 在 西电无人机电装实习 时遇到的问题使用蓝牙芯片 CH582F。沁恒的蓝牙芯片CH582F是一款集成了BLE&#xff08;Bluetooth Low Energy&#xff0…

华为初级认证HCIA怎么样?

想在网络技术领域实现职业突破吗&#xff1f;华为HCIA初级认证是专为网络领域的新手与初学者设计的一项入门级认证。它旨在评估并确认个人对网络基本原理和技术知识的扎实掌握&#xff0c;是步入华为认证体系大门的基石。 一、华为HCIA 初级认证概述 华为初级认证网络工程师&am…

分类预测|基于黑翅鸢优化核极限学习机的数据分类预测Matlab程序BKA-KELM 多特征输入多类别输出 含基础KELM

分类预测|基于黑翅鸢优化核极限学习机的数据分类预测Matlab程序BKA-KELM 多特征输入多类别输出 含基础KELM 文章目录 一、基本原理BKA-HKELM 分类预测原理和流程总结 二、实验结果三、核心代码四、代码获取五、总结 一、基本原理 BKA-HKELM 分类预测原理和流程 1. 黑翅鸢优化…

最好用的翻译器:什么是DeepL?如何订阅支付DeepL,订阅DeepL Pro以及申请DeepL API?

DeepL目前最好用的翻译软件&#xff0c;如果是学习翻译的同学或者海外客户翻译&#xff0c;一定不能错过&#xff0c;用它来处理文件&#xff0c;论文等翻译是最好不过了的&#xff01;&#xff01;&#xff01; AI翻译技术的飞速发展正在颠覆我们的沟通方式&#xff0c;打破语…

6年前倒闭的机器人独角兽,再次杀入AGV市场

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 新书《智能物流系统构成与技术实践》 在科技创新的浪潮中&#xff0c;一个曾经辉煌又迅速陨落的企业正悄然重生&#xff0c;引发业界广泛关注。 曾经的协作机器人鼻祖Rethink Robotic…

机器学习周报(9.9-9.15)-Pytorch学习(三)

文章目录 摘要Abstract1 损失函数与反向传播1.1 L1Loss损失函数1.2 MSELoss损失函数1.3 交叉熵损失函数&#xff08;CrossEntropyLoss&#xff09;1.4 反向传播 2 优化器3 现有网络模型的使用及修改4 网络模型的保存与读取4.1 保存模型4.2 读取 总结 摘要 本次学习对Pytorch中…

8.3Sobel算子边缘检测

实验原理 Sobel算子是一种广泛使用的一阶导数边缘检测算子&#xff0c;它通过计算图像在水平和垂直方向上的梯度来检测边缘。Sobel算子使用一对3x3的掩模来实现这一功能。相比于其他边缘检测算子&#xff0c;Sobel算子在检测边缘的同时还能提供一定的抗噪能力。 在OpenCV中&a…

【射频通信电子线路基础第四讲】LC匹配网络、史密斯圆图、噪声与噪声系数

一、LC匹配网络 1、L-I型&#xff08;负载与电抗并联&#xff09; 2、L-II型&#xff08;负载与电抗串联&#xff09; 3、T型网络和π型网络例子 二、Smith圆图 这里先附上知乎大神的讲解链接&#xff0c;推荐直接去看非常适合入门理解&#xff0c;看完之后茅塞顿开 https://…

MySQL 安全机制全面解析

‍ 在如今的数字化时代&#xff0c;数据库安全 变得越来越重要。为了防止对数据库进行非法操作&#xff0c;MySQL 定义了一套完整的安全机制&#xff0c;包括用户管理、权限管理 和 角色管理。本文将为你深入浅出地介绍这三大安全机制&#xff0c;帮助你轻松掌握MySQL的安全管…