Linux系统调用之mmap,munmap函数

前言

如果,想要深入的学习Linux系统调用中的mmap,munmap函数,还是需要去自己阅读Linux系统中的帮助文档。

具体输入命令:

man 2 mmap/munmap

即可查阅到完整的资料信息。

mmap函数

在Linux中,mmap()是一个用于创建内存映射的系统调用函数。它可以将文件、设备或匿名内存映射到进程的虚拟地址空间。通过内存映射,进程可以直接通过虚拟地址访问映射区域的内容,从而提高文件访问效率,简化数据共享等。

mmap()函数的原型如下:

#include <sys/mman.h> //使用这个函数需导入此头文件
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

参数说明:

  • void *addr: 指定映射区域的起始地址。通常设为NULL,让操作系统自动选择合适的地址。
  • size_t length: 映射区域的大小,以字节为单位。
  • int prot: 映射区域的访问权限。可选值有:
    • PROT_NONE: 不允许访问。
    • PROT_READ: 允许读取。
    • PROT_WRITE: 允许写入。
    • PROT_EXEC: 允许执行。
    • 这些值可以通过按位或(|)运算符组合使用。
  • int flags: 指定映射的类型和其他属性。主要选项有:
    • MAP_SHARED: 创建一个共享映射。对映射区域的修改将写回到文件或共享内存中。
    • MAP_PRIVATE: 创建一个私有映射。对映射区域的修改不会影响其他进程或文件。
    • MAP_FIXED: 使用指定的地址进行映射。不建议使用,因为可能导致现有映射被覆盖。
    • MAP_ANONYMOUS: 创建一个匿名映射。此时,fd参数会被忽略,映射区域不关联任何文件。
    • 使用的方法类似于prot,这些值可以通过按位或(|)运算符组合使用
  • int fd: 文件描述符,指定要映射的文件。对于匿名映射,该参数需设置成-1
  • off_t offset: 文件中的偏移量,表示映射区域的起始位置。通常要求是系统内存页大小的整数倍。

mmap()函数返回值:

  • 成功时返回映射区域的起始地址;
  • 失败时返回MAP_FAILED(通常是(void *)-1)

创建内存映射后,可以使用指针操作映射区域,就像操作普通内存一样。需要注意的是,对映射区域的修改可能会导致文件或共享内存的内容发生变化,具体取决于映射类型(MAP_SHARED或MAP_PRIVATE)。

munmap函数

当我们使用内存映射完毕后,应调用munmap()函数解除内存映射,释放相关资源。

munmap()函数的原型如下:

#include <sys/mman.h> //使用这个函数需导入此头文件
int munmap(void *addr, size_t length);

参数说明:

  • void *addr: 映射区域的起始地址,即mmap()函数的返回值。
  • size_t length: 映射区域的大小,以字节为单位。应与mmap()函数中的length参数相同。

munmap()函数返回值

  • 成功时返回0;
  • 失败时返回-1。

使用匿名映射(内存映射的一种)进行父子进程间通信

下面是一个简单的示例,演示如何使用内存映射技术,利用mmap()和munmap()函数,达到父子间进程间通信的目的。子进程往共享内存中去写数据,父进程去读取子进程写入的数据。

/*
使用内存映射技术,达到父子间进程间通信的目的。子进程往共享内存中去写数据,父进程去读取子进程写入的数据。
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>

int main()
{
    // 打开文件映射(这里使用的是匿名映射,内存映射的一种)
    void *ptr = mmap(NULL, 64, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    if (ptr == MAP_FAILED)
    {
        perror("mmap");
        return -1;
    }
    // 创建子进程
    int pid = fork();
    if (pid > 0)
    {
        wait(NULL); // 等待子进程结束,再从内存映射区读取文件
        printf("来自子进程的信息:%s\n", (char *)ptr);
    }
    else if (pid == 0)
    {
        strcpy((char *)ptr, "hello,world");
    }
    else
    {
        perror("fork");
        munmap(ptr, 64);
        return -1;
    }
    //关闭内存映射
    munmap(ptr, 64);
    return 0;
}

使用mmap函数的易错点

在使用 Linux 的 mmap 函数时,有一些常见的易错点需要注意。下面是一些关键的易错点:

  1. 权限设置错误:在调用 mmap 函数时,需要提供适当的权限。例如,如果要求读写内存,则权限应为 PROT_READ | PROT_WRITE。如果权限设置错误,可能导致访问内存时出现问题。

  2. 文件描述符错误:如果是将文件映射到内存,需要提供正确的文件描述符。如果文件描述符错误,可能导致映射失败。

  3. 错误的文件偏移量:mmap 函数要求文件偏移量为页面大小的整数倍。如果提供了错误的偏移量,函数可能会失败。

  4. 映射长度错误:映射长度应大于零,否则 mmap 会失败。确保提供正确的映射长度。

  5. 映射地址错误:虽然在大多数情况下可以将映射地址设置为 NULL,以便系统选择合适的地址,但在某些情况下,可能需要指定映射地址。确保提供正确的映射地址,否则可能导致错误。

  6. 错误的标志:确保使用正确的标志(例如,MAP_SHARED 或 MAP_PRIVATE)。错误的标志可能导致映射失败或其他问题。

  7. 检查 mmap 返回值:mmap 函数在出错时返回 MAP_FAILED((void *)-1),确保在使用返回的指针之前检查是否为 MAP_FAILED。

  8. 忘记使用 munmap:使用完映射后,不要忘记调用 munmap 函数来解除映射。否则,可能导致资源泄漏。

  9. 多线程同步:如果在多线程环境中使用 mmap,确保在访问映射内存时进行适当的同步。否则,可能导致竞争条件和不一致的数据。

  10. 对匿名映射使用 MAP_FIXED:当需要匿名映射时,避免使用 MAP_FIXED 标志,因为这可能导致覆盖现有映射。通常可以使用 MAP_FIXED_NOREPLACE,以便在指定地址已被使用时,映射失败而不会覆盖现有映射。

注意这些易错点有助于在使用 mmap 函数时避免常见错误,从而提高代码的可靠性和稳定性。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

阿宋同学

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

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

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

打赏作者

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

抵扣说明:

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

余额充值