首页 > 系统相关 >进程通信--内存映射区(用户区)

进程通信--内存映射区(用户区)

时间:2024-05-22 10:52:36浏览次数:23  
标签:共享内存 映射 -- 用户区 内存 shared include shm

在进程间通信(IPC)中,内存映射区(Memory-Mapped Area 或 Memory-Mapped File)是一种高效的通信机制,通过共享内存实现进程间的数据交换。使用内存映射区的主要优点是,它允许不同进程访问同一个物理内存区域,而不需要显式的数据拷贝。

内存映射区的概念

内存映射区是将文件或设备的内容映射到进程的虚拟内存地址空间中。进程可以像操作普通内存一样读写这些映射的区域,而这些操作会直接反映到文件或设备上。对于进程间通信,可以使用匿名内存映射区(不对应具体的文件),进程通过共享这个匿名内存区域来进行数据交换。

使用内存映射区进行进程间通信

步骤

  1. 创建内存映射区

    • 使用 mmap() 系统调用创建内存映射区。匿名内存映射区通常通过打开一个虚拟内存文件(如 /dev/zero)或使用 shm_open() 创建。
  2. 同步访问

    • 多个进程访问同一个共享内存区域时,需要使用同步机制(如信号量或互斥锁)来防止竞争条件和数据不一致。

示例代码

以下是使用内存映射区进行进程间通信的示例:

  1. 父子进程间共享内存
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

int main() {
    // 创建匿名内存映射区
    const size_t SIZE = 4096;
    void *shared_memory = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    if (shared_memory == MAP_FAILED) {
        perror("mmap");
        exit(EXIT_FAILURE);
    }

    pid_t pid = fork();
    if (pid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) {  // 子进程
        // 写入共享内存
        const char *message = "Hello from child process!";
        strcpy((char *)shared_memory, message);
        // 解除内存映射区
        munmap(shared_memory, SIZE);
        exit(EXIT_SUCCESS);
    } else {  // 父进程
        wait(NULL);  // 等待子进程
        // 读取共享内存
        printf("Parent read: %s\n", (char *)shared_memory);
        // 解除内存映射区
        munmap(shared_memory, SIZE);
        exit(EXIT_SUCCESS);
    }
}

代码解析

  1. 创建内存映射区

    void *shared_memory = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    
    • mmap() 用于创建一个匿名内存映射区。MAP_SHARED 标志表示这个映射区可以在多个进程间共享。MAP_ANONYMOUS 标志表示这个映射区不与任何文件关联。
  2. 进程间通信

    • 父进程使用 fork() 创建子进程。
    • 子进程在共享内存区域写入数据。
    • 父进程等待子进程结束,然后从共享内存区域读取数据。
  3. 解除内存映射

    munmap(shared_memory, SIZE);
    
    • 使用 munmap() 解除内存映射区,释放资源。

使用 shm_openmmap

shm_openmmap 可以结合使用,创建命名共享内存区域,使无亲缘关系的进程间通信变得可能。

以下是使用 shm_openmmap 的示例:

  1. 进程A(创建和写入共享内存)

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/mman.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <string.h>
    
    int main() {
        const char *name = "/my_shm";
        const size_t SIZE = 4096;
    
        int shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
        if (shm_fd == -1) {
            perror("shm_open");
            exit(EXIT_FAILURE);
        }
    
        if (ftruncate(shm_fd, SIZE) == -1) {
            perror("ftruncate");
            exit(EXIT_FAILURE);
        }
    
        void *shared_memory = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
        if (shared_memory == MAP_FAILED) {
            perror("mmap");
            exit(EXIT_FAILURE);
        }
    
        const char *message = "Hello from process A!";
        strcpy((char *)shared_memory, message);
    
        munmap(shared_memory, SIZE);
        close(shm_fd);
        return 0;
    }
    
  2. 进程B(读取共享内存)

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/mman.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <string.h>
    
    int main() {
        const char *name = "/my_shm";
        const size_t SIZE = 4096;
    
        int shm_fd = shm_open(name, O_RDONLY, 0666);
        if (shm_fd == -1) {
            perror("shm_open");
            exit(EXIT_FAILURE);
        }
    
        void *shared_memory = mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
        if (shared_memory == MAP_FAILED) {
            perror("mmap");
            exit(EXIT_FAILURE);
        }
    
        printf("Read from shared memory: %s\n", (char *)shared_memory);
    
        munmap(shared_memory, SIZE);
        close(shm_fd);
        shm_unlink(name);
        return 0;
    }
    

代码解析

  1. 创建和写入共享内存

    • shm_open 创建或打开一个命名共享内存对象。
    • ftruncate 设置共享内存对象的大小。
    • mmap 将共享内存对象映射到进程的地址空间。
    • 写入数据到共享内存。
  2. 读取共享内存

    • shm_open 以只读模式打开命名共享内存对象。
    • mmap 将共享内存对象映射到进程的地址空间。
    • 读取数据。
  3. 清理

    • 使用 munmap 解除内存映射。
    • 使用 close 关闭文件描述符。
    • 使用 shm_unlink 删除命名共享内存对象。

通过内存映射区进行进程间通信,可以实现高效的共享内存访问,这对于需要频繁且高速的数据交换的应用非常有用。

标签:共享内存,映射,--,用户区,内存,shared,include,shm
From: https://www.cnblogs.com/whcjob/p/18205745

相关文章

  • 全面了解网络性能监测与流量分析
    当前数字化时代,网络系统的复杂性与日俱增,网络性能监测和流量分析已成为网络管理的关键所在。本文将从多个角度为您剖析网络性能监测和流量分析的精髓,助您深入了解网络的运行脉搏。网络性能监测:把握关键指标网络性能监测涉及多个重要方面:带宽监控及时掌握网络带宽使用状况......
  • 接口测试用例设计的关键步骤与技巧解析
    简介接口测试在需求分析完成之后,即可设计对应的接口测试用例,然后根据用例进行接口测试。接口测试用例的设计也需要用到黑盒测试用例设计方法,和测试流程与理论章节的功能测试用例设计的方法类似,设计过程中还需要增加与接口特性相关的测试用例。接口测试流程接口测试的质量目标......
  • 主流原型设计工具概览
    当代主流原型设计工具概览在数字产品开发领域,原型设计是至关重要的一步。它不仅帮助设计师和开发团队可视化产品概念,还能在产品开发周期的早期阶段发现潜在问题。随着技术的发展,市面上涌现出许多优秀的原型设计工具,它们各有特点,适用于不同的设计需求和工作流程。本文将介绍几种主......
  • word替换快捷操作
    Sub替换词语()DimdocAsDocumentDimfindTextAsStringDimreplaceTextAsString'设置第一个要查找和替换的文本findText="机构管理"replaceText="部门管理"'获取当前活动文档Setdoc=ActiveDocument'开始第一个查找和替换......
  • mysql 分组加行号
    mysql示例SELECTcasewhen@currentid<>t.idthen@rownum:=1else@rownum:=@rownum+1endASrow_num,casewhen@currentid<>t.idthen@currentid:=t.idelse@currentidendASrow_num,ID,......
  • DockerFile
    DockerFile介绍DockeFile是用来构建docker镜像的描述文件,命令参数的脚本。构建步骤1、编写一个dockerfile文件2、dockerbuild构建成为一个镜像3、dockerrun运行镜像4、dockerpush发布镜像DockerFile构建过程基础知识:1、每个保留关键字(指令)都是必须是大写字母2......
  • Java核心面试知识集—Kafka面试题
    目录基础篇1、TCP、UDP的区别?2、TCP协议如何保证可靠传输?3、TCP的握手、挥手机制?4、TCP的粘包/拆包原因及其解决方法是什么?5、Netty的粘包/拆包是怎么处理的,有哪些实现?6、同步与异步、阻塞与非阻塞的区别?7、说说网络IO模型?8、BIO、NIO、AIO分别是什么?9、select、poll、epoll的机制......
  • LLM-文心一言:modbus、opc、can、mqtt协议
    Modbus、OPC、CAN和MQTT都是不同的通信协议,它们在工业自动化、物联网和其他领域有着广泛的应用。以下是对这些协议的简要介绍:Modbus:Modbus是一种串行通信协议,由Modicon公司(现为施耐德电气的一部分)在1979年提出,用于可编程逻辑控制器(PLC)之间的通信。它已经成为工业领域通信协议的......
  • springboot集成logback-spring.xml日志文件
    logback-spring.xml:<!--Logbackconfiguration.Seehttp://logback.qos.ch/manual/index.html--><configurationscan="true"scanPeriod="10seconds"><springPropertyscope="context"name="logLevel"s......
  • shell(一)
    shell(一)单选题1、在bash中,快捷键【Ctrl+Z】的作用是什么?A、中止前台任务B、给当前文件加上.eofC、将前台任务转入后台D、注销当前用户2、使用sed命令删除文件file中的所有文本行开头的空格,下列命令正确的是。A、sed-r's/^\s+//g'fileB、.sed-r'/^./s*///g'file......