Linux使用mmap实现父子进程间的通信

 更新时间:2025年11月27日 09:23:40   作者:郝学胜-神的一滴  
在Linux系统中,进程间通信(IPC)是编程中常见的需求,传统的IPC方式包括管道、消息队列、共享内存、信号量等,mmap函数可以将文件映射到进程的地址空间,也可以用于创建匿名映射,从而实现进程间的内存共享,本文将详细介绍如何在Linux中使用mmap实现父子进程间的通信

引言

在Linux系统中,进程间通信(IPC)是编程中常见的需求。传统的IPC方式包括管道、消息队列、共享内存、信号量等。其中,共享内存是一种高效的IPC方式,因为它允许不同进程直接读写同一块内存区域,而不需要内核的介入。mmap(memory map)函数可以将文件映射到进程的地址空间,也可以用于创建匿名映射,从而实现进程间的内存共享。本文将详细介绍如何在Linux中使用mmap实现父子进程间的通信。

一、mmap基本概念

mmap是Linux系统提供的一个系统调用,用于将文件或设备映射到进程的地址空间。通过mmap,进程可以像访问内存一样访问文件或设备,而无需使用传统的read/write系统调用。

mmap函数原型如下:

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

参数说明:

  • addr:指定映射的起始地址,通常设为NULL让系统自动选择
  • length:映射区域的长度
  • prot:保护标志,如PROT_READ(可读)、PROT_WRITE(可写)等
  • flags:映射类型标志,如MAP_SHARED(共享)、MAP_PRIVATE(私有)等
  • fd:文件描述符,��于匿名映射设为-1
  • offset:映射的文件偏移量,通常为0

mmap成功时返回映射区域的起始地址,失败时返回MAP_FAILED((void*)-1)。

二、父子进程创建方式

在Linux中,可以通过多种方式创建父子进程:

  1. fork():创建一个与父进程几乎完全相同的子进程
  2. vfork():创建一个与父进程共享地址空间的子进程
  3. clone():更灵活地创建进程,可以指定共享的资源

最常用的是fork()函数,它创建的子进程是父进程的一个副本,拥有独立的地址空间。但是,通过mmap创建的匿名映射区域可以在父子进程间共享。

三、使用mmap实现父子进程通信

下面我们通过一个示例来展示如何使用mmap实现父子进程间的通信:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <fcntl.h>

#define SHM_SIZE 1024

int main() {
    // 使用mmap创建匿名映射
    void *shared_mem = mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    if (shared_mem == MAP_FAILED) {
        perror("mmap failed");
        exit(EXIT_FAILURE);
    }

    pid_t pid = fork();
    
    if (pid < 0) {
        perror("fork failed");
        exit(EXIT_FAILURE);
    } else if (pid == 0) {
        // 子进程代码
        printf("Child process writing to shared memory\n");
        strcpy((char *)shared_mem, "Hello from child process!");
        
        // 子进程结束
        exit(EXIT_SUCCESS);
    } else {
        // 父进程代码
        // 等待子进程结束
        wait(NULL);
        
        printf("Parent process reading from shared memory: %s\n", (char *)shared_mem);
        
        // 解除映射
        if (munmap(shared_mem, SHM_SIZE) == -1) {
            perror("munmap failed");
            exit(EXIT_FAILURE);
        }
    }
    
    return 0;
}

代码解析:

  1. 首先使用mmap创建一个大小为1024字节的匿名映射区域,设置保护标志为PROT_READ | PROT_WRITE,表示可读可写;设置映射类型为MAP_SHARED | MAP_ANONYMOUS,表示这是一个共享的匿名映射。
  2. 使用fork()创建子进程。子进程会继承父进程的地址空间,包括mmap创建的共享内存区域。
  3. 在子进程中,向共享内存写入一条消息:“Hello from child process!”。
  4. 父进程通过wait()等待子进程结束,然后从共享内存中读取子进程写入的消息并打印。
  5. 最后,使用munmap()解除映射,释放共享内存资源。

四、注意事项和最佳实践

  1. 同步问题:由于多个进程可以同时访问共享内存,可能会出现数据竞争问题。可以使用信号量、互斥锁等同步机制来保证数据的一致性。
  2. 内存保护:合理设置mmap的保护标志,避免不必要的读写权限,提高安全性。
  3. 错误处理:对mmap、fork等系统调用进行充分的错误检查,确保程序的健壮性。
  4. 资源释放:确保在程序结束前调用munmap释放映射的内存区域,避免内存泄漏。
  5. 大小选择:根据实际需求选择合适的共享内存大小,避免浪费或不足。

五、扩展应用

mmap不仅可以用于父子进程间通信,还可以用于:

  1. 无亲缘关系的进程间通信:通过将文件映射到内存,不同进程可以访问同一个文件实现通信。
  2. 内存映射文件:将大文件映射到内存,可以高效地访问文件内容,而不需要将整个文件读入内存。
  3. 虚拟内存管理:mmap是Linux虚拟内存管理系统的重要组成部分,用于管理进程的地址空间。

六、进阶示例:带同步的父子进程通信

下面是一个更复杂的示例,展示了如何在父子进程间使用mmap和信号量进行同步通信:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>

#define SHM_SIZE 1024
#define SEM_NAME "/my_semaphore"

typedef struct {
    char message[SHM_SIZE];
    int ready;
} SharedData;

int main() {
    // 创建或打开信号量
    sem_t *sem = sem_open(SEM_NAME, O_CREAT, 0644, 0);
    if (sem == SEM_FAILED) {
        perror("sem_open failed");
        exit(EXIT_FAILURE);
    }
    
    // 使用mmap创建匿名映射
    SharedData *shared_data = mmap(NULL, sizeof(SharedData), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    if (shared_data == MAP_FAILED) {
        perror("mmap failed");
        exit(EXIT_FAILURE);
    }
    
    pid_t pid = fork();
    
    if (pid < 0) {
        perror("fork failed");
        exit(EXIT_FAILURE);
    } else if (pid == 0) {
        // 子进程代码
        printf("Child process writing to shared memory\n");
        strcpy(shared_data->message, "Hello from child process with synchronization!");
        shared_data->ready = 1;
        
        // 通知父数据已准备好
        if (sem_post(sem) == -1) {
            perror("sem_post failed");
            exit(EXIT_FAILURE);
        }
        
        // 子进程结束
        exit(EXIT_SUCCESS);
    } else {
        // 父进程代码
        // 等待子进程通知
        if (sem_wait(sem) == -1) {
            perror("sem_wait failed");
            exit(EXIT_FAILURE);
        }
        
        printf("Parent process reading from shared memory: %s\n", shared_data->message);
        
        // 解除映射
        if (munmap(shared_data, sizeof(SharedData)) == -1) {
            perror("munmap failed");
            exit(EXIT_FAILURE);
        }
        
        // 关闭并删除信号量
        if (sem_close(sem) == -1) {
            perror("sem_close failed");
            exit(EXIT_FAILURE);
        }
        
        if (sem_unlink(SEM_NAME) == -1) {
            perror("sem_unlink failed");
            exit(EXIT_FAILURE);
        }
    }
    
    return 0;
}

这个示例展示了如何使用信号量来同步父子进程对共享内存的访问,确保父进程在子进程写入数据后才能读取数据。

七、总结

mmap是一种高效的进程间通信方式,特别适合需要大量数据交换的场景。通过合理使用mmap,可以实现父子进程间的高效通信。本文介绍了mmap的基本概念、父子进程创建方式,以及使用mmap实现父子进程通信的具体方法和注意事项。希望读者能够通过本文掌握mmap的使用,并在实际编程中灵活应用。

以上就是关于Linux父子进程使用mmap通信的详细介绍。mmap作为一种高效的IPC机制,在系统编程中有着广泛的应用。通过合理使用mmap,可以大大提高进程间通信的效率,减少数据拷贝的开销。

以上就是Linux使用mmap实现父子进程间的通信的详细内容,更多关于Linux mmap父子进程通信的资料请关注脚本之家其它相关文章!

相关文章

  • 让Apache支持Rewrite静态页面重写的方法

    让Apache支持Rewrite静态页面重写的方法

    Apache下Rewrite静态页面重写的方法,需要的朋友可以参考下。
    2010-07-07
  • Ubuntu 16.04源码编译安装Apache 2.4.25教程

    Ubuntu 16.04源码编译安装Apache 2.4.25教程

    这篇文章主要为大家详细介绍了Ubuntu 16.04源码编译安装Apache 2.4.25,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-01-01
  • Linux网桥配置br-lan、eth0、eth1、ra0、rai0方式

    Linux网桥配置br-lan、eth0、eth1、ra0、rai0方式

    这篇文章主要介绍了Linux网桥配置br-lan、eth0、eth1、ra0、rai0方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • CentOS 部署 flask项目的方法

    CentOS 部署 flask项目的方法

    本篇文章主要介绍了CentOS 部署 flask项目的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01
  • 解析Linux高性能网络IO和Reactor模型

    解析Linux高性能网络IO和Reactor模型

    网络I/O,可以理解为网络上的数据流。通常我们会基于socket与远端建立一条TCP或者UDP通道,然后进行读写。单个socket时,使用一个线程即可高效处理;然而如果是10K个socket连接,或者更多,我们如何做到高性能处理
    2021-06-06
  • centos7防火墙如何设置只对部分端口号限源

    centos7防火墙如何设置只对部分端口号限源

    这篇文章主要介绍了centos7防火墙如何设置只对部分端口号限源问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-06-06
  • apache启用gzip压缩的实现方法

    apache启用gzip压缩的实现方法

    对于部署在Linux服务器上的PHP程序,在服务器支持的情况下,我们建议你开启使用Gzip Web压缩,以前脚本之家介绍了iis中的开启方法,这篇文章主要介绍了linux中apache的开启方法
    2013-06-06
  • Linux下查看binlog文件创建时间的命令

    Linux下查看binlog文件创建时间的命令

    这篇文章主要介绍了Linux下查看binlog文件创建时间的命令,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-05-05
  • 将你的Apache速度提高十倍的经验分享

    将你的Apache速度提高十倍的经验分享

    你知道吗,如果你的web server是采用apache那你就有机会通过安装一个软件模块提高你的网站访问速度,最大能有10倍之多!这可不是吹牛,你看看原理就明白了
    2013-04-04
  • Linux使用vmstat监控系统性能的示例方法

    Linux使用vmstat监控系统性能的示例方法

    vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存使用,虚拟内存交换情况,IO读写情况,本文给大家介绍了Linux使用vmstat监控系统性能的示例方法,需要的朋友可以参考下
    2025-03-03

最新评论