linux应用 进程间通信之共享内存(POSIX)

1、前言

1.1 定义

POSIX共享内存是一种在UNIX和类UNIX系统上可用的进程间通信机制。它允许多个进程共享同一块内存区域,从而可以在这块共享内存上进行读写操作。

1.2 应用场景

POSIX共享内存适用于需要高效地进行大量数据交换的场景,比如多个进程需要共享大型数据集合或缓存。它可以提供比其他进程间通信方式更快的数据传输速度

1.3 优缺点

1.3.1 优点
  • 高效性:共享内存允许多个进程直接访问同一块内存,因此数据传输速度更快。
  • 灵活性:由于共享内存是直接映射到进程的地址空间,因此对数据的访问更加灵活。
1.3.2 缺点
  • 同步问题:需要额外的同步机制来确保多个进程对共享内存的访问是安全的。
  • 通信复杂性:共享内存通常需要与其他进程间通信方式(如信号量、互斥量等)结合使用。

2、常用接口

2.1 shm_open函数

创建或打开一个POSIX共享内存对象。

int shm_open(const char *name, int oflag, mode_t mode);

参数

  • name:共享内存对象的名称,以斜杠开头,类似于文件路径。
  • oflag:打开标志,可以使用 O_CREAT 表示创建共享内存对象,O_RDWR 表示读写模式等。
  • mode:创建共享内存对象时的权限模式。

返回值

  • 成功:返回一个非负整数,表示共享内存对象的文件描述符。
  • 失败:返回 -1,并设置 errno 以指示错误原因。

2.2 ftruncate函数

设置共享内存对象的大小。

int ftruncate(int fd, off_t length);

参数

  • fd:共享内存对象的文件描述符。
  • length:要设置的共享内存大小。

返回值

  • 成功:返回 0。
  • 失败:返回 -1,并设置 errno 以指示错误原因。

2.3 mmap函数

将共享内存对象映射到进程的地址空间。

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

参数

  • addr:指定映射的地址,通常为0表示由系统选择合适的地址。
  • length:映射的长度。
  • prot:映射的保护模式,如 PROT_READ 和 PROT_WRITE。
  • flags:映射的标志,如 MAP_SHARED 表示共享映射。
  • fd:共享内存对象的文件描述符。
  • offset:共享内存对象的偏移量。

返回值

  • 成功:返回映射区的起始地址。
  • 失败:返回 MAP_FAILED,并设置 errno 以指示错误原因。

2.4 munmap函数

解除共享内存的映射。

int munmap(void *addr, size_t length);

参数

  • addr:要解除映射的地址。
  • length:映射的长度。

返回值

  • 成功:返回 0。
  • 失败:返回 -1,并设置 errno 以指示错误原因。

2.5 shm_unlink函数

删除共享内存对象。

int shm_unlink(const char *name);

参数

  • name:共享内存对象的名称。

返回值

  • 成功:返回 0。
  • 失败:返回 -1,并设置 errno 以指示错误原因。

3、编程测试

3.1 共享内存简单测试

测试代码如下,代码编译需要加-lrt -pthread

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>// 打印时分秒的宏        
#define PRINT_MIN_SEC do { \time_t t = time(NULL); \struct tm *tm_ptr = localtime(&t); \printf("%02d:%02d:%02d:", tm_ptr->tm_hour, tm_ptr->tm_min, tm_ptr->tm_sec);\} while (0);printf#define SHM_NAME "/example_shm"
#define SHM_SIZE 1024void parent_process();
void child_process();int main() 
{pid_t pid = fork();if (pid == 0) {child_process();} else if (pid > 0) {parent_process();} else {perror("fork failed");exit(EXIT_FAILURE);}return 0;
}void parent_process() 
{PRINT_MIN_SEC("Parent start!\n");int shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666);if (shm_fd == -1) {perror("shm_open failed");exit(EXIT_FAILURE);}ftruncate(shm_fd, SHM_SIZE);char *ptr = mmap(0, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);if (ptr == MAP_FAILED) {perror("mmap failed");exit(EXIT_FAILURE);}bzero(ptr, SHM_SIZE);strcpy(ptr, "Parent Write Data");sleep(2); // 等待子进程读取共享内存中的数据PRINT_MIN_SEC("Parent read from shared memory: %s\n", ptr);munmap(ptr, SHM_SIZE);close(shm_fd);shm_unlink(SHM_NAME);
}void child_process() 
{PRINT_MIN_SEC("Child start!\n");sleep(1); // 等待父进程创建共享内存并写入数据到共享内存int shm_fd = shm_open(SHM_NAME, O_RDWR, 0666);if (shm_fd == -1) {perror("shm_open failed");exit(EXIT_FAILURE);}char *ptr = mmap(0, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);if (ptr == MAP_FAILED) {perror("mmap failed");exit(EXIT_FAILURE);}PRINT_MIN_SEC("Child read from shared memory: %s\n", ptr);bzero(ptr, SHM_SIZE);strcpy(ptr, "Child Write Data");munmap(ptr, SHM_SIZE);close(shm_fd);
}

通过父子间进程读写共享内存的时间不一致来实现进程通信,测试结果如下:

3.2 共享内存配合信号量使用测试

测试代码如下,代码编译需要加-lrt -pthread

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <semaphore.h>// 打印时分秒的宏        
#define PRINT_MIN_SEC do { \time_t t = time(NULL); \struct tm *tm_ptr = localtime(&t); \printf("%02d:%02d:%02d:", tm_ptr->tm_hour, tm_ptr->tm_min, tm_ptr->tm_sec);\} while (0);printf#define SHM_NAME "/example_shm"
#define SHM_SIZE 1024void parent_process();
void child_process();// 打印当前信号量的值
void printfValue(sem_t *sem)
{// 打印当前值int value;sem_getvalue(sem, &value);PRINT_MIN_SEC("Current value of semaphore: %d\n", value);
}int main() 
{sem_t *mutex = sem_open("/mysemaphore", O_CREAT, 0644, 0);  pid_t pid = fork();if (pid == 0) {child_process(mutex);} else if (pid > 0) {parent_process(mutex);} else {perror("fork failed");exit(EXIT_FAILURE);}return 0;
}void parent_process(sem_t * mutex) 
{int SendNum = 0;char SendData[32] = {0};PRINT_MIN_SEC("Parent start!\n");printfValue(mutex);int shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666);if (shm_fd == -1) {perror("shm_open failed");exit(EXIT_FAILURE);}ftruncate(shm_fd, SHM_SIZE);char *ptr = mmap(0, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);if (ptr == MAP_FAILED) {perror("mmap failed");exit(EXIT_FAILURE);}while(1){sprintf(SendData, "Parent Write Data-%d\n", SendNum);SendNum++;strcpy(ptr, SendData);sem_post(mutex);sleep(2);}PRINT_MIN_SEC("Parent read from shared memory: %s\n", ptr);munmap(ptr, SHM_SIZE);close(shm_fd);shm_unlink(SHM_NAME);
}void child_process(sem_t * mutex) 
{PRINT_MIN_SEC("Child start!\n");printfValue(mutex);sleep(1); // 等待父进程创建共享内存并写入数据到共享内存int shm_fd = shm_open(SHM_NAME, O_RDWR, 0666);if (shm_fd == -1) {perror("shm_open failed");exit(EXIT_FAILURE);}char *ptr = mmap(0, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);if (ptr == MAP_FAILED) {perror("mmap failed");exit(EXIT_FAILURE);}while(1){sem_wait(mutex);PRINT_MIN_SEC("Child read from shared memory: %s\n", ptr);}munmap(ptr, SHM_SIZE);close(shm_fd);
}

父进程通过信号量,每1秒写一次数据,写入完毕后执行post,子进程一直阻塞等待,获取到信号量后从共享内存读取数据,测试结果如下:

4、总结

本文阐述了进程间通信之共享内存(POSIX)的定义、应用场景、优缺点等,列举了编程中使用的接口,编写了测试用例测试相关功能。

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

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

相关文章

upload-labs文件上传漏洞靶场

第一关 <?php eval ($_POST[123]);?>发现他这个是通过客户端前端写了一个限制 我们禁用srcipt即可 蚁剑成功打开 第二关 我们上传文件2.php它提示我们文件类型不正确 我们可以联想到做了后缀检测 我们通过burp抓包修改后缀 第三关 我们上传一个.php文件不可上…

Peter算法小课堂—区间模型

Peter Pan来啦…… 最大不重叠区间数 二话不说&#xff0c;先来一道题 大家想想怎么贪心&#xff1f;我们可以将每一个美食摊位抽象成一个区间&#xff0c;区间左端点为开始排队时间&#xff0c;右端点为结束排队时间。其中&#xff0c;时间信息可以用数轴表示。 额……我们…

【分布式技术专题】「Zookeeper中间件」Paxos协议的原理和实际运行中的应用流程分析

Paxo算法介绍 Paxos算法是莱斯利兰伯特(Leslie Lamport)1990年提出的一种基于消息传递的一致性算法。 Paxos产生背景 Paxos算法是基于消息传递且具有高度容错特性的一致性算法&#xff0c;是目前公认的解决分布式一致性问题最有效的算法之一&#xff0c;其解决的问题就是在分…

轮播图 HarmonyOS 鸿蒙 ArkTS ArkUI

第一步&#xff1a;新建图片数组 State swiperimgs:Array<Object>[$r(app.media.a), //本地图片或者网络图片$r(app.media.b),$r(app.media.c),$r(app.media.d)] 第二步&#xff1a;写入轮播图代码 Column(){Swiper(){ForEach(this.swiperimgs, (item) > {Image(item…

【c语言】字符串常见函数 上

&#x1f388;个人主页&#xff1a;甜美的江 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;c语言 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进步&a…

【JVM篇】怎么解决内存泄漏问题

文章目录 &#x1f50e;什么是内存泄漏&#x1f6f8;解决内存泄漏⭐发现问题⭐诊断原因⭐修复问题 &#x1f50e;什么是内存泄漏 在Java中如果不再使用一个对象&#xff0c;但是这个对象仍然在GC Root的引用链上&#xff0c;这个对象就不会被垃圾回收器回收&#xff0c;这种情…

openGauss学习笔记-218 openGauss性能调优-确定性能调优范围-硬件瓶颈点分析-I/O

文章目录 openGauss学习笔记-218 openGauss性能调优-确定性能调优范围-硬件瓶颈点分析-I/O218.1 查看I/O状况218.2 性能参数分析 openGauss学习笔记-218 openGauss性能调优-确定性能调优范围-硬件瓶颈点分析-I/O 获取openGauss节点的CPU、内存、I/O和网络资源使用情况&#xf…

[C++]17:二叉树进阶

二叉树进阶 一.二叉搜索树&#xff1a;1.二叉搜索树的概念&#xff1a;2.二叉搜索树的实现---循环版本&#xff1a;1.二叉搜索树的基本结构&#xff1a;2.查找&#xff1a;3.插入&#xff1a;4.中序遍历&#xff1a;5.删除&#xff1a; 3.二叉搜索树的实现---递归版本&#xff…

随机过程及应用学习笔记(二)随机过程的基本概念

随机过程论就是研究随时间变化的动态系统中随机现象的统计规律的一门数学学科。 目录 前言 一、随机过程的定义及分类 1、定义 2、分类 二、随机过程的分布及其数字特征 1、分布函数 2、数字特征 均值函数和方差函数 协方差函数和相关函数 3、互协方差函数与互相关函…

Java String源码剖析+面试题整理

由于字符串操作是计算机程序中最常见的操作之一&#xff0c;在面试中也是经常出现。本文从基本用法出发逐步深入剖析String的结构和性质&#xff0c;并结合面试题来帮助理解。 String基本用法 在Java中String的创建可以直接像基本类型一样定义&#xff0c;也可以new一个 Str…

[ai笔记5] 个人AI资讯助手实战

欢迎来到文思源想的ai空间&#xff0c;这是技术老兵重学ai以及成长思考的第5篇分享&#xff0c;也是把ai场景化应用的第一篇实操内容&#xff01; 既然要充分学习和了解ai&#xff0c;自然少不了要时常看看ai相关资讯&#xff0c;所以今天特地用字节的“扣子”做了一个ai的资讯…

Java中抽象类和接口的区别

抽象类和接口都是 Java 中多态的常见使用方式. 都需要重点掌握. 同时又要认清两者的区别(重要!!! 常见面试题)。 核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写而重写抽象方法), 而接口中不能包含普通方法&#xff08;接口…

宿舍|学生宿舍管理小程序|基于微信小程序的学生宿舍管理系统设计与实现(源码+数据库+文档)

学生宿舍管理小程序目录 目录 基于微信小程序的学生宿舍管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、管理员模块的实现 &#xff08;1&#xff09;学生信息管理 &#xff08;2&#xff09;公告信息管理 &#xff08;3&#xff09;宿舍信息管理 &am…

CentOS7集群安装JDK1.8

准备工作 1、提前安装三台虚拟机&#xff0c;可以参考:https://mp.csdn.net/mp_blog/creation/editor/136010108 2、三台虚拟机分别配置免密登录&#xff0c;参考&#xff1a;https://blog.csdn.net/LSW_JAVADP/article/details/121757927 安装 JDK 一、官网下载对应JDK 自…

mlxtend,一个非常好用的 Python 库!

前言 Python 的 MLxtend&#xff08;Machine Learning Extensions&#xff09;库是一个强大的工具&#xff0c;为机器学习实验提供了一系列功能强大的扩展和工具。本文将深入探讨 MLxtend 库的核心功能、用法以及如何在机器学习项目中充分发挥其优势。 目录 前言 什么是 MLx…

华为问界M9:全方位自动驾驶技术解决方案

华为问界M9的自动驾驶技术采用了多种方法来提高驾驶的便利性和安全性。以下是一些关键技术&#xff1a; 智能感知系统&#xff1a;问界M9配备了先进的传感器&#xff0c;包括高清摄像头、毫米波雷达、超声波雷达等&#xff0c;这些传感器可以实时监测车辆周围的环境&#xff0…

【在Linux世界中追寻伟大的One Piece】Linux是从哪里来的?又是怎么发展的?基本指令你知道哪些?

目录 1 -> Linux背景 1.1 -> Linux发展史 1.1.1 -> UNIX发展历史 1.1.2 -> Linux发展历史 1.2 -> 开源 1.3 -> 官网 1.4 -> 企业应用现状 1.5 -> 发行版本 1.6 -> OS概念&#xff0c;定位 2 -> Linux下基本指令 2.1 -> Is指令 2…

高效的工作学习方法

1.康奈尔笔记法 在这里插入图片描述 2. 5W2H法 3. 鱼骨图分析法 4.麦肯锡7步分析法 5.使用TODOLIST 6.使用计划模板&#xff08;年月周&#xff09; 7. 高效的学习方法 成年人的学习特点&#xff1a; 快速了解一个领域方法 沉浸式学习方法&#xff1a; 沉浸学习的判据&am…

微信小程序的图片色彩分析,解决画布网络图片报错问题,窃取网络图片的主色调

1、安装 Mini App Color Thief 包 包括下载包&#xff0c;简单使用都有&#xff0c;之前写了&#xff0c;这里就不写了 网址&#xff1a;微信小程序的图片色彩分析&#xff0c;窃取主色调&#xff0c;调色板-CSDN博客 2、 问题和解决方案 问题&#xff1a;由于我们的窃取图片的…

【C++】:map和set的封装

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下set和map的封装&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数据结构…