内核空间<---->用户空间互传之mmap技术

引言

        内核空间与用户空间的通信一般可以通过用驱动方式实现,相对于使用mmap技术来说比较复杂;mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。

一.mmap基本概念

        mmap 是 Unix 和 Linux 系统中的一个系统调用,用于在进程的地址空间中映射文件或设备到内存区域。这样,文件或设备的内容就像被加载到内存中一样,可以直接通过指针来访问,而无需使用传统的 read 和 write 系统调用来读写数据。mmap 提供了一种高效的方式来处理大文件或频繁访问的数据。

        

二. mmap相关函数

#include <sys/mman.h>  
  
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

参数说明

  • addr:建议的映射区域的起始地址。通常设置为 NULL,让系统自动选择地址。
  • length:要映射的字节数。
  • prot:映射区域的保护标志,如 PROT_READPROT_WRITE 和 PROT_EXEC。可以组合使用。
  • flags:指定映射的类型和特性,如 MAP_SHARED 或 MAP_PRIVATE
  • fd:文件描述符,通常是一个已经打开的文件或设备的描述符。
  • offset:从文件中开始映射的偏移量。

特性与用途

  1. 共享映射 (MAP_SHARED): 当多个进程映射同一个文件时,并且使用 MAP_SHARED 标志,一个进程对映射区域的修改会立即反映到文件和所有其他映射了该文件的进程中。这是进程间通信(IPC)的一种高效方式。
  2. 私有映射 (MAP_PRIVATE): 如果使用 MAP_PRIVATE 标志,对映射区域的修改不会反映到原始文件或其他映射了该文件的进程中。这通常用于创建一个文件的“副本”在内存中,以便进行读写操作,而无需直接修改文件。
  3. 文件锁定与内存映射mmap 可以与文件锁定机制(如 fcntl 的 F_SETLK 和 F_GETLK 操作)一起使用,以实现对映射区域的同步访问,防止多个进程同时修改同一数据。
  4. 效率mmap 通常比传统的 read 和 write 调用更高效,因为它减少了内核和用户空间之间的数据复制次数(通过所谓的“零拷贝”技术)。
  5. 大文件处理: 对于非常大的文件,使用 mmap 可以避免一次性将整个文件加载到内存中,而是按需加载文件的某一部分。

注意事项

  • 当不再需要映射区域时,应使用 munmap 系统调用来释放它。
  • 在使用 mmap 时,必须确保正确地处理错误和异常情况,以避免数据损坏或资源泄漏。
  • mmap 的行为可能受到操作系统、文件系统和其他因素的影响,因此在使用它之前,最好查阅相关文档和参考资料。

三.例子

int main(int argc, char *argv[]) {  
    int fd;  
    void *data;  
    size_t length;  
    off_t offset = 0;  
  
    // 检查命令行参数  
    if (argc != 2) {  
        fprintf(stderr, "Usage: %s <filename>\n", argv[0]);  
        exit(EXIT_FAILURE);  
    }  
  
    // 打开文件  
    fd = open(argv[1], O_RDONLY);  
    if (fd == -1) {  
        perror("Error opening file");  
        exit(EXIT_FAILURE);  
    }  
  
    // 获取文件大小  
    struct stat fileStat;  
    if (fstat(fd, &fileStat) == -1) {  
        perror("Error getting file size");  
        close(fd);  
        exit(EXIT_FAILURE);  
    }  
    length = fileStat.st_size;  
  
    // 映射文件到内存  
    data = mmap(NULL, length, PROT_READ, MAP_SHARED, fd, offset);  
    if (data == MAP_FAILED) {  
        perror("Error mmapping the file");  
        close(fd);  
        exit(EXIT_FAILURE);  
    }  
  
    // 关闭文件描述符(此时文件仍然映射在内存中)  
    close(fd);  
  
    // 在内存中读取文件内容  
    char *p = (char *)data;  
    char buffer[1024];  
    ssize_t bytesRead;  
  
    while ((bytesRead = read(STDIN_FILENO, buffer, sizeof(buffer) - 1)) > 0) {  
        // 在这个例子中,我们只是简单地将文件内容打印到标准输出  
        // 实际上,你可以对映射的内存区域进行任何操作,就像操作普通内存一样  
        write(STDOUT_FILENO, p, bytesRead);  
        p += bytesRead;  
    }  
  
    // 解除映射  
    if (munmap(data, length) == -1) {  
        perror("Error un-mmapping the file");  
        exit(EXIT_FAILURE);  
    }  
  
    return 0;  
}

  • 25
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我来挖坑啦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值