【Linux进程间通信】四、mmap共享存储映射

简介: 【Linux进程间通信】四、mmap共享存储映射

1. 什么是存储映射IO

存储映射I/O (Memory-mapped I/O) 使一个磁盘文件与存储空间(内存)中的一个缓冲区相映射。这样的话,当从缓冲区中取数据,就相当于读文件中的相应的字节,而将数据存入缓冲区,则相应的字节就自动写入文件。这样,就可在不使用read和write函数的情况下,使用地址(指针)完成I/O操作,当然也可以使用内存操作函数strcpy,memcpy等。

使用这种方法,首先应通知内核,将一个指定文件映射到存储区域中。这个映射工作可以通过mmap函数来实现。

2. mmap函数介绍

2.1 mmap函数创建映射区

  • 包含头文件
#include <sys/mman.h>
  • 函数原型
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
void *mmap64(void *addr, size_t length, int prot, int flags, int fd, off64_t offset);
int munmap(void *addr, size_t length);
  • 函数功能
    mmap() creates a new mapping in the virtual address space of the calling process. The starting address for the new mapping is specified in addr. The length argument specifies the length of the mapping.
  • 函数参数
  • addr:建立映射区的首地址,由Linux内核指定,使用时直接传递NULL 。
  • length:想要创建的映射区的大小 。
  • prot:映射区权限
  • PROT_READ:可读
  • PROT_WRITE:可写(PROT_READ | PROT_WRITE 读写)
  • PROT_EXEC:可执行
  • PROT_NONE:不可用
  • flags:标志位参数,常用于设定更新物理区域、设置共享、创建匿名映射区
  • MAP_SHARED:共享的,会将映射区所做的操作反映到物理设备(磁盘)上。也就是说,对内存的修改会影响到源文件。
  • MAP_PRIVATE:私有的,映射区所做的修改不会反映到物理设备(磁盘)。
  • fd:用来建立映射区的文件描述符,映射区是从文件映射来的,所以创建映射区肯定要打开一个文件。
  • offset:偏移量,映射文件的偏移(4k的整数倍)。
  • 函数返回值
  • On success, mmap() returns a pointer to the mapped area. 成功返回创建的映射区首地址。
  • On error, the value MAP_FAILED (that is, (void *) -1) is returned, and errno is set appropriately. 失败返回一个宏MAP_FAILED,并设置errno。

2.2 munmap函数释放映射区

  • 包含头文件
#include <sys/mman.h>
  • 函数原型
int munmap(void *addr, size_t length);
  • 函数功能
    释放mmap创建的映射区(可以联想malloc/free, new/delete等内存管理函数对)。
  • 函数参数
  • addr:mmap的返回值(由mmap返回的映射区首地址)
  • length:mmap创建的映射区的长度
  • 函数返回值
  • On success, munmap() returns 0.
  • On failure returns -1, and errno is set (probably to EINVAL).

3. mmap函数用法示例及注意事项

/************************************************************
  >File Name  : mmap_test.c
  >Author     : Mindtechnist
  >Company    : Mindtechnist
  >Create Time: 2022年05月22日 星期日 15时52分45秒
************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
int main(int argc, char* argv[])
{
    int fd = open("mem.txt", O_RDWR);
    /*int fd = open("mem.txt", O_RDWR | O_CREAT | O_TRUNC, 0644); 创建文件并截断
    ftruncate(fd, 8); 新创建文件必须进行扩展,大小不能为0*/
    char* mem = mmap(NULL, 8, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    /*char* mem = mmap(NULL, 8, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);*/
    if(mem == MAP_FAILED)
    {
        perror("mmap err");
        return -1;
    }
    /*我们操作的是内存,但是这种操作会被同步到文件*/
    strcpy(mem, "hello"); /*写入字符串,所以mmap()返回char*类型*/
    int mret = munmap(mem, 8);
    if(mret < 0)
    {
        perror("munmap err");
    }
    close(fd);
    return 0;
}

mmap函数使用时的注意事项:

  • 使用mmap()函数创建缓冲区返回的地址mem是多少,munmap()释放的时候传入的参数mem就是多少,不能更改,也就是说,要把mmap()返回的地址原模原样传进munmap()才能正常释放。(munmap传入的地址一定是mmap的返回地址,不能对地址指针进行++等位移操作。)
  • mem.txt文件的大小对映射区操作也是有影响的,如果我们设置的映射缓冲区为len,而实际上的mem.txt文件大小大于len,假如说我们写入映射区的内容大于len,只要不超过文件大小,也是可以写进去的。如果写入的内容大于文件的长度,那么超出文件长度的部分就被截断。
  • 文件偏移量必须为4K的整数倍。mmap()函数中,最后一个参数偏移量必须是4K的整数倍,这是操作系统的限制,文件最小门槛就是8个512,也就是4096。如果一个文件本身大小没有达到4K,那么它占用的空间大小也是4096。比如下面mem.txt实际上只有10字节大小,但是占据了8个512,这就证明文件最小占据4K空间。

  • 映射区的释放与文件关闭无关,只要映射建立成功,文件可以立即关闭。这是因为,只要使用mmap()函数映射完缓冲区,那么这个映射区和文件之间的通道已经建立,即使提前关闭文件描述符,也不影响对映射区和文件的操作。
  • 如果文件mem.txt的为0,也就是空文件,那么会报错“总线错误(核心已转储)”,所以映射时使用的文件大小不能是0(当映射文件大小为0时,不能创建映射区,用于映射的文件必须要有实际大小。mmap使用时常常会出现总线错误,通常是由于共享文件存储空间大小引起的)。

  • 创建映射区的过程中,隐含着一次对映射文件的读操作,所以open打开文件时,必须要有读权限。
  • 当MAP_SHARED时,要求:映射区的权限应小于等于文件打开的权限(出于对映射区的保护,因为映射区的操作会影响文件)。而MAP_PRIVATE则无所谓,因为mmap中的权限是对内存的限制。
  • mmap创建映射区时出错概率非常高,一定要检查返回值,确保映射区建立成功再进行后续操作。


相关文章
|
29天前
|
算法 Linux 调度
深入理解Linux操作系统的进程管理
本文旨在探讨Linux操作系统中的进程管理机制,包括进程的创建、执行、调度和终止等环节。通过对Linux内核中相关模块的分析,揭示其高效的进程管理策略,为开发者提供优化程序性能和资源利用率的参考。
66 1
|
18天前
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
83 13
|
25天前
|
SQL 运维 监控
南大通用GBase 8a MPP Cluster Linux端SQL进程监控工具
南大通用GBase 8a MPP Cluster Linux端SQL进程监控工具
|
1月前
|
运维 监控 Linux
Linux操作系统的守护进程与服务管理深度剖析####
本文作为一篇技术性文章,旨在深入探讨Linux操作系统中守护进程与服务管理的机制、工具及实践策略。不同于传统的摘要概述,本文将以“守护进程的生命周期”为核心线索,串联起Linux服务管理的各个方面,从守护进程的定义与特性出发,逐步深入到Systemd的工作原理、服务单元文件编写、服务状态管理以及故障排查技巧,为读者呈现一幅Linux服务管理的全景图。 ####
|
2月前
|
缓存 算法 Linux
Linux内核的心脏:深入理解进程调度器
本文探讨了Linux操作系统中至关重要的组成部分——进程调度器。通过分析其工作原理、调度算法以及在不同场景下的表现,揭示它是如何高效管理CPU资源,确保系统响应性和公平性的。本文旨在为读者提供一个清晰的视图,了解在多任务环境下,Linux是如何智能地分配处理器时间给各个进程的。
|
2月前
|
Linux 网络安全 数据安全/隐私保护
Linux 超级强大的十六进制 dump 工具:XXD 命令,我教你应该如何使用!
在 Linux 系统中,xxd 命令是一个强大的十六进制 dump 工具,可以将文件或数据以十六进制和 ASCII 字符形式显示,帮助用户深入了解和分析数据。本文详细介绍了 xxd 命令的基本用法、高级功能及实际应用案例,包括查看文件内容、指定输出格式、写入文件、数据比较、数据提取、数据转换和数据加密解密等。通过掌握这些技巧,用户可以更高效地处理各种数据问题。
138 8
|
2月前
|
监控 Linux
如何检查 Linux 内存使用量是否耗尽?这 5 个命令堪称绝了!
本文介绍了在Linux系统中检查内存使用情况的5个常用命令:`free`、`top`、`vmstat`、`pidstat` 和 `/proc/meminfo` 文件,帮助用户准确监控内存状态,确保系统稳定运行。
552 6
|
2月前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
104 3
|
2月前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
88 2
|
29天前
|
Linux Shell
Linux 10 个“who”命令示例
Linux 10 个“who”命令示例
53 14
Linux 10 个“who”命令示例