【Linux】mmap文件映射的使用

目录

mmap文件映射介绍

参数介绍:

返回值介绍:

对文件进行操作的常用系统调用

写入映射

读取映射

使用mmap极简模拟实现malloc


mmap文件映射介绍

允许用户空间程序将文件或设备的内容直接映射到进程的虚拟地址空间中,通过mmap程序可以高效的方法问文件数据,而无需通过调用传统的read或write进行数据的复制。

参数介绍:

  • addr:表示希望映射区域在进程地址空间中的开始虚拟地址,如果是NULL,则操作系统会自动选择一个合适的地址。
  • length:要映射到进程地址空间中的字节数,这个大小必须是操作系统页面大小的整数倍(通常是4KB也就是4096B,不同的操作系统页面大小可能不同)。如果指定的len大小不是系统页面大小的整数倍,系统可能会自动向上舍入到最近的页面大小边界。
  • prot:指定映射区域的内存保护属性,可以是以下组合(使用按位或|运算符)。PROT_READ:映射区域可读。PROT_WRITE:映射区域可写。PROT_EXEC:映射区域可执行。
  • flags:指定映射的类型和其他选项。MAP_PRIVATE:私有映射,对映射区域的修改不会反映到底层文件中。MAP_SHARED:共有映射,对映射区域的修改会反映到底层文件中(前提是文件是以写的方式打开的)。其他选项(MAP_ANONYMOUS)用于创建不与文件关联的匿名映射。
  • fd:一个文件描述符,指向要映射的文件。对于匿名映射,这个参数为-1 。
  • offset:文件中的起始偏移量,从文件那个位置的内容开始映射。

返回值介绍:

成功返回进程地址空间中的映射的区域对应的开始的虚拟地址。

失败返回MAP_FAILED,其实就是(void*)-1 。

对文件进行操作的常用系统调用

调整文件大小的系统调用truncate和ftruncate:

获取文件状态信息的系统调用stat和fsate:

写入映射

cpp 复制代码
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/man.h>
#include <unistd.h>
#include <fcntl.h>

#define PAGE_SIZE 4096
enum Status
{
    USAGE_ERROR = 1,
    OPEN_ERROR = 2,
    FTRUNCATE_ERROR = 3,
    MMAP_ERROR = 4,
    MUNMAP_ERROR = 5
};

int main(int argc, char* argv[])
{
    if(argc != 2){
        std::cerr << "Usage: " << argv[0] << " filename" << std::endl;
        return USAGE_ERROR;
    }
    
    //映射不存在的文件先创建该文件
    int fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0666);
    if(fd < 0){
        std::cerr << "Failed to open file: " << argv[1] << std::endl;
        return OPEN_ERROR;
    }

    if(ftruncate(fd, PAGE_SIZE) == -1){
        std::cerr << "Failed to ftruncate file: " << argv[1] << std::endl;
        return FTRUNCATE_ERROR; 
    }

    char* addr = (char*)::mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if(addr == MAP_FAILED){
        std::cerr << "Failed to mmap file: " << argv[1] << std::endl;
        return MMAP_ERROR;
    }

    //向文件中写入数据
    for(int i = 'A';i < 'Z';++i)
    {
        addr[i-'A'] = 'A' + i;
        sleep(1);
    }

    if(::munmap(addr, PAGE_SIZE) == -1){
        std::cerr << "Failed to munmap file: " << argv[1] << std::endl;
        return MUNMAP_ERROR;
    }

    close(fd);
    return 0;
}

读取映射

cpp 复制代码
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/man.h>
#include <unistd.h>
#include <fcntl.h>

#define PAGE_SIZE 4096
enum Status
{
    USAGE_ERROR = 1,
    OPEN_ERROR = 2,
    FTRUNCATE_ERROR = 3,
    MMAP_ERROR = 4,
    MUNMAP_ERROR = 5
};

int main(int argc, char* argv[])
{
    if(argc != 2){
        std::cerr << "Usage: " << argv[0] << " filename" << std::endl;
        return USAGE_ERROR;
    }
    
    int fd = open(argv[1], O_RDONLY);
    if(fd < 0){
        std::cerr << "Failed to open file: " << argv[1] << std::endl;
        return OPEN_ERROR;
    }

    //获取文件属性
    struct stat st;
    ::fstat(fd, &st);

    char* addr = (char*)::mmap(nullptr, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
    if(addr == MAP_FAILED){
        std::cerr << "Failed to mmap file: " << argv[1] << std::endl;
        return MMAP_ERROR;
    }

    //读取文件中的数据
    std::cout << "File content: " << addr << std::endl;

    if(::munmap(addr, st.st_size) == -1){
        std::cerr << "Failed to munmap file: " << argv[1] << std::endl;
        return MUNMAP_ERROR;
    }

    close(fd);
    return 0;
}

使用mmap极简模拟实现malloc

cpp 复制代码
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <sys/mman.h>
#include <unistd.h>

void* my_malloc(size_t size)
{
    if(size <= 0){
        return nullptr;
    }
    void* addr = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if(addr == (void*)-1){
        perror("mmap");
        return nullptr;
    }
    return addr;
}

void myf_free(void* ptr, size_t size)
{
    if(!ptr && size > 0){
        if(::munmap(ptr, size) == -1){
            perror("munmap");
        }
    }
}

int main()
{
    size_t size = 1024;
    char* ptr = (char*)my_malloc(size);
    if(ptr){
        memset(ptr,'A',size);
        for(int i = 0;i < size;++i){
        printf("%c ", ptr[i]);
        fflush(stdout);
        sleep(1);
    }
   }
    my_free(ptr, size);

    return 0;
}
相关推荐
IT猿手9 分钟前
基于控制障碍函数的多无人机编队动态避障控制方法研究,MATLAB代码
开发语言·matlab·无人机·openclaw·多无人机动态避障路径规划·无人机编队
AI科技星18 分钟前
全尺度角速度统一:基于 v ≡ c 的纯推导与验证
c语言·开发语言·人工智能·opencv·算法·机器学习·数据挖掘
sunwenjian88632 分钟前
Java进阶——IO 流
java·开发语言·python
波特率11520038 分钟前
const关键字与函数的重载
开发语言·c++·函数重载
FL16238631291 小时前
[C#][winform]segment-anything分割万物部署onnx模型一键抠图演示
开发语言·c#
百锦再1 小时前
Java 并发编程进阶,从线程池、锁、AQS 到并发容器与性能调优全解析
java·开发语言·jvm·spring·kafka·tomcat·maven
条tiao条1 小时前
KMP 算法详解:告别暴力匹配,让字符串匹配 “永不回头”
开发语言·算法
todoitbo1 小时前
用虚拟局域网打通 Win/Mac/Linux 三端:跨设备协作的实用方案
linux·运维·macos
干啥啥不行,秃头第一名1 小时前
C++20概念(Concepts)入门指南
开发语言·c++·算法
源远流长jerry1 小时前
RDMA 基本操作类型详解:从双端通信到单端直访
linux·网络·tcp/ip·ip