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 1024

void 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 1024


void 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)的定义、应用场景、优缺点等,列举了编程中使用的接口,编写了测试用例测试相关功能。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

消息中间件特点

1.  消息中间件概念 消息中间件是消息传递的过程中保存消息的容器。 主要目的&#xff1a;提供路由并保证消息的传递&#xff1b;如果发送消息时接受者不可用&#xff0c;消息队列会保留信息&#xff0c;直到可以成功传递为止。 消息中间件保存消息也是有期限的。 2.  消息…

openGauss学习笔记-217 openGauss性能调优-确定性能调优范围-硬件瓶颈点分析-内存

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

加固平板电脑丨三防智能平板丨工业加固平板丨智能城市管理

随着智能城市的不断发展&#xff0c;人们对于城市管理的要求也在不断提高&#xff0c;这就需要高效、智能的城市管理平台来实现。而三防平板就是一款可以满足这一需求的智能设备。 三防平板是一种集防水、防尘、防摔于一体的智能平板电脑&#xff0c;它可以在复杂的环境下稳定运…

《Think in Java》

《Think in Java》 第一章&#xff1a;对象导论 1.1 抽象过程 1&#xff09;万物皆对象。 2&#xff09;程序是对象的集合&#xff0c;它们通过发送消息来告诉彼此所要做的。 3&#xff09;每个对象都有其他对象构成的存储&#xff0c;一个对象可以复用其他对象&#xff0c;从而…

【C++】模版初阶

目录 泛函编程 函数模版 概念 格式 原理 实例化 模版函数的匹配原则 类模板 定义格式 泛函编程 如何实现一个通用的交换函数呢&#xff1f; void Swap(int& left, int& right) {int temp left;left right;right temp; } void Swap(double& left, dou…

搜索专项---最小步数模型

文章目录 魔板 一、魔板OJ链接 本题思路:最小步数模型: 将整个“图”视为一个状态也即一个节点. 状态的转移视为权值为1的边. BFS求解, 注意几点: 状态的存储: 一般用字符串存储状态, 用哈希表存储初始状态到每个状态的距离. 方案记录: 记忆数组存储. 本题中需要存储上一个状…

低资源学习与知识图谱:构建与应用

目录 前言1 低资源学习方法1.1 数据增强1.2 特征增强1.3 模型增强 2 低资源知识图谱构建与推理2.1 元关系学习2.2 对抗学习2.3 零样本关系抽取2.4 零样本学习与迁移学习2.5 零样本学习与辅助信息 3 基于知识图谱的低资源学习应用3.1 零样本图像分类3.2 知识增强的零样本学习3.3…

5秒!全网最简单的幻兽帕鲁服务器搭建教程来了!

幻兽帕鲁官方服务器不稳定&#xff1f;自己搭建幻兽帕鲁服务器&#xff0c;低延迟、稳定不卡&#xff0c;目前阿里云和腾讯云均推出幻兽帕鲁专用服务器&#xff0c;腾讯云直接提供幻兽帕鲁镜像系统&#xff0c;阿里云通过计算巢服务&#xff0c;均可以一键部署&#xff0c;鼠标…

【C++初阶:类和对象(下篇)】初始化列表 | static成员 | 友元

目录 一、构造函数构造函数体赋值&#x1f43e;初始化列表&#x1f43e;&#x1f4a6; explicit关键字 二、static成员&#x1f43e;概念**&#x1f4a6; 关于静态的特性** 三、友元&#x1f4a6; **友元函数**&#x1f4a6; **友元类** **四、内部类** 一、构造函数 构造函数…

CSS之水平垂直居中

如何实现一个div的水平垂直居中 <div class"content-wrapper"><div class"content">content</div></div>flex布局 .content-wrapper {width: 400px;height: 400px;background-color: lightskyblue;display: flex;justify-content:…

每日一练——月落乌啼算钱

题目&#xff1a; 举例&#xff1a; 输入&#xff1a;6&#xff0c;输出&#xff1a;8.00 最开始看到这道题还有点蒙&#xff0c;但是看到他的公式想起了斐波那契数列 1,1,2,3,5,8...... 由前两个数相加得到第三个数&#xff0c;为An2An1An。 可以得出这个题目中所给的通项就…

【Chrono Engine学习总结】4-vehicle-4.2-车辆轨迹跟踪

由于Chrono的官方教程在一些细节方面解释的并不清楚&#xff0c;自己做了一些尝试&#xff0c;做学习总结。 0、Vehicle的driver driver在上一篇总结中有过介绍&#xff0c;【Chrono Engine学习总结】4-vehicle-4.1-vehicle的基本概念&#xff0c;这里进一步介绍。 对于一个…

1 月 NFT 市场动态:Polygon 增长,Mooar 崛起,TinFun 掀起文化浪潮

作者&#xff1a;stellafootprint.network 数据源&#xff1a;NFT Research - Footprint Analytics 2024 年 1 月&#xff0c;加密货币与 NFT 市场迎来了重要的转折点&#xff0c;其中美国首批现货比特币 ETF 的亮相尤为引人注目&#xff0c;这一金融一体化的里程碑事件吸引了…

Java学习第十三节之下标越界及四个基本特点

下标越界 数组的四个基本特点 package array;public class ArrayDemo03 {public static void main(String[] args) {int[] arrays {1,2,3,4,5,};//打印全部的数组元素for (int i 0; i <arrays.length; i) {System.out.println(arrays[i]);}System.out.println(""…

WEB APIs(1)

变量声明const&#xff08;修饰常量&#xff09; const优先&#xff0c;如react&#xff0c;基本const&#xff0c; 对于引用数据类型&#xff0c;可用const声明&#xff0c;因为储存的是地址 何为APIs 可以使用js操作HTML和浏览器 分类&#xff1a;DOM&#xff08;文档对象…

利用Pygame处理键盘事件

在游戏开发中&#xff0c;处理用户输入是至关重要的一部分。玩家的键盘操作可以控制游戏中的角色移动、交互和其他行为&#xff0c;因此游戏如何响应键盘事件将直接影响玩家的游戏体验。在Pygame中&#xff0c;处理键盘事件是一个基础且重要的技能&#xff0c;本文将介绍Pygame…

如何生成狗血短剧

如何生成狗血短剧 狗血短剧剧本将上述剧本转成对话 狗血短剧剧本 标题&#xff1a;《爱的轮回》 类型&#xff1a;现代都市爱情短剧 角色&#xff1a; 1. 林晓雪 - 女&#xff0c;25岁&#xff0c;职场小白&#xff0c;善良单纯 2. 陆子轩 - 男&#xff0c;28岁&#xff0c;公…

Qt QWidget以及各种控件、布局 核心属性(适合入门使用时查询)

目录 1. QWidget核心属性 2. 按钮类控件 2.1 PushButton 核心属性 2.2 RadioButton 核心属性 2.3 CheckBox 和 Tool Button 核心属性 3. 显示类控件 3.1 Label 核心属性 3.2 LCDNumber 核心属性 3.3 ProgressBar 核心属性 3.4 Calendar Widget 核心属性 4. 输入类控…

Java基于 SpringBoot 的高校校园点餐系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

猫头虎分享已解决Bug || ModuleNotFoundError: No module named ‘tensorflow‘

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …