Linux操作系统4-进程间通信5(共享内存实现两个进程通信)

news2025/2/23 6:18:57

上篇文章:Linux操作系统4-进程间通信4(共享内存原理,创建,查看,命令)-CSDN博客

本篇Gitee仓库:myLerningCode/l24 · 橘子真甜/Linux操作系统与网络编程学习 - 码云 - 开源中国 (gitee.com)

本篇重点:进程关联与去关联共享内存,实现两个进程通信

一. 进程关联共享内存

        两个进程想要通过共享内存进行通信,在创建共享内存之后还需要将这个共享内存与我们的进程相关联。

 进程关联共享内存的系统调用如下:

//头文件
#include <sys/types.h>
#include <sys/shm.h>

//函数原型
void* shmat(int shmid, const void* shmarr, int shmflg)

//参数
shimid 想要关联共享内存的id
shmarr 想要关联共享内存的地址空间,一般设置为NULL
shmflg 一般设置为0

//返回值
返回共享内存通过页表映射到进程地址空间的起始地址

二. 进程去关联共享内存 

        在我们使用完了这段共享内存后,如果想要让其他进程进行通信。可以让当前的进程与共享内存去关联

系统调用如下:

//头文件
#include <sys/types.h>
#include <sys/shm.h>

int shmdt(const void* shmaddr);

shmaddr 我们关联共享内存时候获取的地址

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

三. 删除共享内存 

        在上篇文章中,我们使用命令 ipcs -m 查看共享内存。使用命令 ipcrm -m 删除共享内存

我们也可以通过系统调用来删除共享内存

系统调用如下:

#include <sys/ipc.h>
#include <sys/shm.h>

//用于对共享内存的控制(包含删除)
int shmctl(int shmid, int cmd, struct shmid_ds *buf)

cmd:传入的二进制标志位
IPC_RMID:立即移除对应的共享内存

buf:删除的话直接设置为NULL即可

返回值,失败返回-1,错误码被设置

四. 实现通信 

4.1 common.hpp

        这个头文件用于实现创建,关联,去关联,删除共享内存的代码。之后只需要让server.cpp和client.cpp去调用代码即可。

创建共享内存:对于client和server来说,需要由不同的操作,server需要创建共享内存,并且存在共享内存需要出错返回,而client只需要获取共享内存的id即可

代码如下:

#include <iostream>

#include <cassert>
#include <cstring>
#include <cstdlib>

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <error.h>
#include <unistd.h>

// 当前的绝对路径用于获取key
#define PATHNAME "."
#define PROJ_ID 2025221
#define MAXSIZE 5

// 获取key值
key_t getKey()
{
    // 获取一个key
    key_t key = ftok(PATHNAME, PROJ_ID);
    assert(key != -1);
}

// 传入key,创建共享内存,并返回其id
// flag是为了区分不同的进程,创建共享内存的进程需要出错返回,而另一个进程则不需要
int getShmHelp(const key_t key, int flag)
{
    int sid = shmget(key, MAXSIZE, flag);
    assert(sid >= 0);
}

// 共享内存存在,需要出错返回,并且提供权限
int creatShm(key_t key)
{
    return getShmHelp(key, IPC_CREAT | IPC_EXCL | 0666);
}

// 存在共享内存,不做任何事,只是返回id
int getShm(key_t key)
{
    return getShmHelp(key, IPC_CREAT);
}

关联共享内存:传入id,关联共享内存,返回地址空间的起始地址即可

// 关联共享内存与进程
void *attachShm(int shmid)
{
    void *mem = shmat(shmid, nullptr, 0);
    if ((long long)mem == -1l) // 指针占8字节
    {
        std::cerr << "attachShm error" << errno << ":" << strerror(errno) << std::endl;
        exit(1);
    }
    return mem;
}

去关联共享内存:传入id,去关联即可

// 去关联共享内存
void detachShm(void *start)
{
    int n = shmdt(start);
    if (n == -1)
    {
        std::cerr << "detachShm error" << errno << ":" << strerror(errno) << std::endl;
        exit(2);
    }
}

 删除共享内存:传入id,删除即可

// 删除共享内存
void deleteShm(int shmid)
{
    int n = shmctl(shmid, IPC_RMID, nullptr);
    if (n == -1)
    {
        std::cerr << "deleteShm error" << errno << ":" << strerror(errno) << std::endl;
        exit(3);
    }
}

4.2 server.cpp

        共享内存通信让进程地址空间与共享内存通过页表进行了映射,所以我们只需要直接向字符串一样输出信息即可。

server端接收来自client端发送的消息

代码如下:

#include "common.hpp"
#include <iostream>
#include <string>

int main()
{
    // 1.创建共享内存
    int shmid = creatShm(getKey());
    std::cout << "server 创建共享内存成功" << std::endl;

    // 2.关联共享内存和进程地址空间的映射
    char *start = (char *)attachShm(shmid);
    std::cout << "server 关联共享内存成功" << std::endl;
    sleep(5);

    // 开始通信
    while (true)
    {
        // 服务端接收信息,由于有地址空间的映射。
        // 我们只需要和字符串一样接收即可
        std::cout << start << std::endl;
        sleep(1);
    }

    // 3.去关联共享内存与进程地址空间的映射
    detachShm(start);
    std::cout << "server 去关联共享内存成功" << std::endl;

    // 4.强制删除共享内存
    deleteShm(shmid);
    std::cout << "server 删除共享内存成功" << std::endl;

    return 0;
}

4.3 client.cpp 

client端无需删除共享内存

#include "common.hpp"
#include <iostream>

int main()
{
    // 获取共享内存id
    int shmid = getShm(getKey());
    std::cout << "client 获取共享内存id成功" << " sid为" << shmid << std::endl;

    // 关联共享内存
    char *start = (char *)attachShm(shmid);
    std::cout << "client 关联共享内存成功" << std::endl;

    // 开始通信
    const char *message = "你好server,我是client ...";
    int cnt = 0;
    while (true)
    {
        snprintf(start, MAXSZIE, "%s[client pid:%d][消息编号:%d]", start, getpid(), cnt++);
        sleep(1);
    }

    // 去关联共享内存
    detachShm(start);
    std::cout << "client 去关联共享内存成功" << std::endl;

    // client无需删除共享内存,server删除
    return 0;
}

五. 分析测试结果

        运行测试结果如下:

先运行server,在运行ckient。可以看到server端成功接收来自client的消息

 我们让client关闭

 关闭client端之后,server端仍然打印最后一条65编号的信息。

这说明共享内存没有同步和互斥功能,如果想要实现这个功能需要我们加锁

六. 共享内存的特定与优缺点

        6.1 优点

共享内存的优点就是

是所有进程间通信中最快的,只要我们一方写入数据,另外一方可以直接看到,大大减少数据的拷贝次数

 因为共享内存不需要缓冲区,所以速度快。这里我们对比共享内存与管道通信

管道通信:

共享内存通信

 

        在不考虑键盘输入,显示器输出的情况下。

管道文件至少需要拷贝数据4次,而共享内存只需要拷贝数据两次。

很明显。共享内存大大减少的数据的拷贝次数 

6.2 缺点 

        在上面的测试中我们知道,共享内存的缺点是:不支持同步和互斥功能,如果读取速度较快,会读取到已经读取了的数据

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

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

相关文章

RFID测温技术:电力设备安全监测的新利器

在当今高度依赖电力的现代化社会中&#xff0c;稳定且可靠的电力供应是社会运转的基石。电力设备作为电力系统的关键核心&#xff0c;其运行状态直接关乎电力供应的品质。然而&#xff0c;电力设备长期运行过程中&#xff0c;受到诸如过载、接触不良以及环境因素等多重影响&…

(一)趣学设计模式 之 单例模式!

目录 一、啥是单例模式&#xff1f;二、为什么要用单例模式&#xff1f;三、单例模式怎么实现&#xff1f;1. 饿汉式&#xff1a;先下手为强&#xff01; &#x1f608;2. 懒汉式&#xff1a;用的时候再创建&#xff01; &#x1f634;3. 枚举&#xff1a;最简单最安全的单例&a…

自动化办公|xlwings生成图表

在日常的数据分析和报告生成中&#xff0c;Excel图表是一个非常重要的工具。它能够帮助我们直观地展示数据&#xff0c;发现数据中的规律和趋势。然而&#xff0c;手动创建和调整图表往往耗时且容易出错。幸运的是&#xff0c;借助Python的xlwings库&#xff0c;我们可以自动化…

Docker基于Ollama本地部署大语言模型

一、Ollama介绍 Ollama 是一个开源的大型语言模型&#xff08;LLM&#xff09;平台&#xff0c;旨在简化大型语言模型在本地环境中的运行、管理和交互。通过Ollama&#xff0c;用户可以轻松加载和使用各种预训练的语言模型&#xff0c;执行诸如文本生成、翻译、代码编写、问答…

centos9安装k8s集群

以下是基于CentOS Stream 9的Kubernetes 1.28.2完整安装流程&#xff08;containerd版&#xff09;&#xff1a; 一、系统初始化&#xff08;所有节点执行&#xff09; # 关闭防火墙 systemctl disable --now firewalld# 关闭SELinux sed -i "s/SELINUXenforcing/SELINU…

pytest下allure

import pytestdef test_case01():用例01~print(用例01)class Test_mokuai01:def test_case02(self):用例02~print(用例02)if __name____main__:#pytest.main([-vs,test_sample-2.py])pytest.main([-vs,test_sample-2.py,--allure-dir,./result2])#生成allure报告&#xff0c;参…

JVM预热

阿里电商平台每年的各种大促活动&#xff0c;对于Java技术来说&#xff0c;其中重要一个操作环节就是预热操作。 目录 预热是什么&#xff1f;为什么要预热&#xff1f; java 程序不预热和预热的调用对比 预热是什么&#xff1f; 预热是指&#xff0c;在 JVM 启动后&#xff0…

【JavaWeb12】数据交换与异步请求:JSON与Ajax的绝妙搭配是否塑造了Web的交互革命?

文章目录 &#x1f30d;一. 数据交换--JSON❄️1. JSON介绍❄️2. JSON 快速入门❄️3. JSON 对象和字符串对象转换❄️4. JSON 在 java 中使用❄️5. 代码演示 &#x1f30d;二. 异步请求--Ajax❄️1. 基本介绍❄️2. JavaScript 原生 Ajax 请求❄️3. JQuery 的 Ajax 请求 &a…

网页制作06-html,css,javascript初认识のhtml如何建立超链接

超链接有外部链接、电子邮件链接、锚点链接、空链接、脚本链接 一、内部链接 与自身网站页面有关的链接被称为内部链接 1、创建内部链接 1&#xff09;语法&#xff1a; <a href"链接地址"> …… </a> 2&#xff09;举例应用&#xff1a; 3&#xf…

代码讲解系列-CV(七)——前沿论文复现

文章目录 一、论文速览1.1 确定baseline1.2 DepthMaster: Taming Diffusion Models for Monocular Depth Estimation 二、数据环境搭建2.1 环境搭建2.2 数据权重 三、推理debug3.1 单图推理3.2 数据集验证 四、模型训练4.1 数据读取4.2 训练流程 五、作业 一、论文速览 1.1 确…

数据库面试知识点总结

目录 1. MySQL 基础题1.1 执行⼀条 select / update 语句&#xff0c;在 MySQL 中发生了什么&#xff1f;1.2 MySQL 一行记录是怎么存储的&#xff1f; 2. 三大范式3. 数据库引擎3.1 Innodb3.2 MyISAM 4. 数据库索引4.1 索引分类4.2 索引优缺点4.3 索引使用场景4.4 优化索引方法…

1.25作业

1easytornado SSTI——tornado模板 hints.txt&#xff1a;在/fllllllllllllag里&#xff1b;计算filehash的方法&#xff08;需要cookie_secret,对filename进行md5拼接再第二次md5&#xff09; ?filename/hints.txt&filehash{ {2*3}}&#xff0c;跳转到另一个页面 存在且…

Power Query M函数

文章目录 三、PQ高阶技能&#xff1a;M函数3.1 M函数基本概念3.1.1 表达式和值3.1.2 计算3.1.3 运算符3.1.4 函数3.1.5 元数据3.1.6 Let 表达式3.1.6 If 表达式3.1.7 Error 3.2 自定义M函数3.2.1 语法3.2.2 调用定义好的自定义函数3.2.3 直接调用自定义函数3.2.4 自定义函数&am…

python argparse 解析命令行参数

可选参数 带 - 或者 -- 的参数都是可选参数&#xff0c;如果命令行不输入&#xff0c;得到的结果是 None 参数名只能使用下划线&#xff0c;不能使用中划线 default&#xff1a; 设置默认值 action&#xff1a; 默认是 store 方法&#xff0c;常用的是 store_true 命令行出…

【网络编程】服务器模型(二):并发服务器模型(多线程)和 I/O 复用服务器(select / epoll)

一、多线程并发服务器 在 高并发的 TCP 服务器 中&#xff0c;单线程或 fork() 多进程 方式会导致 资源浪费和性能瓶颈。因此&#xff0c;我们可以使用 多线程 来高效处理多个客户端的连接。 承接上文中的多进程并发服务器&#xff0c;代码优化目标&#xff1a; 1.使用 pthr…

自学Java-AI结合GUI开发一个石头迷阵的游戏

自学Java-AI结合GUI开发一个石头迷阵的游戏 准备环节1、创建石头迷阵的界面2、打乱顺序3、控制上下左右移动4、判断是否通关5、统计移动步骤&#xff0c;重启游戏6、拓展问题 准备环节 技术&#xff1a; 1、GUI界面编程 2、二维数组 3、程序流程控制 4、面向对象编程 ∙ \bulle…

Liunx(CentOS-6-x86_64)系统安装MySql(5.6.50)

一&#xff1a;安装Liunx&#xff08;CentOS-6-x86_64&#xff09; 安装Liunx&#xff08;CentOS-6-x86_64&#xff09; 二&#xff1a;下载MySql&#xff08;5.6.50&#xff09; MySql下载官网 二&#xff1a;安装MySql 2.1 将mysql上传到Liunx 文件地址 /usr/local/ 2…

Java Web开发实战与项目——开发一个在线论坛系统

在线论坛系统是一个常见的Web应用&#xff0c;通常具有用户注册、帖子发布、评论互动、消息推送等基本功能。开发这样一个系统&#xff0c;既涉及到前后端的技术栈选择&#xff0c;也需要考虑性能、扩展性等实际问题。本文将从设计论坛模块、实现消息推送与实时更新功能、以及优…

ubuntu24.04无法安装向日葵,提示依赖libgconf-2-4怎么办?

在向日葵官方下载的deb包&#xff0c;目前是SunloginClient_15.2.0.63062_amd64.deb&#xff0c;执行安装代码&#xff0c;如下&#xff1a; sudo < /span > dpkg< /span > -i< /span > SunloginClient_15< /span >.2< /span >.0< /span >…

Kubernetes 使用 Kube-Prometheus 构建指标监控 +飞书告警

1 介绍 Prometheus Operator 为 Kubernetes 提供了对 Prometheus 机器相关监控组件的本地部署和管理方案&#xff0c;该项目的目的是为了简化和自动化基于 Prometheus 的监控栈配置&#xff0c;主要包括以下几个功能&#xff1a; Kubernetes 自定义资源&#xff1a;使用 Kube…