前言
如果,想要深入的学习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 函数时,有一些常见的易错点需要注意。下面是一些关键的易错点:
-
权限设置错误:在调用 mmap 函数时,需要提供适当的权限。例如,如果要求读写内存,则权限应为 PROT_READ | PROT_WRITE。如果权限设置错误,可能导致访问内存时出现问题。
-
文件描述符错误:如果是将文件映射到内存,需要提供正确的文件描述符。如果文件描述符错误,可能导致映射失败。
-
错误的文件偏移量:mmap 函数要求文件偏移量为页面大小的整数倍。如果提供了错误的偏移量,函数可能会失败。
-
映射长度错误:映射长度应大于零,否则 mmap 会失败。确保提供正确的映射长度。
-
映射地址错误:虽然在大多数情况下可以将映射地址设置为 NULL,以便系统选择合适的地址,但在某些情况下,可能需要指定映射地址。确保提供正确的映射地址,否则可能导致错误。
-
错误的标志:确保使用正确的标志(例如,MAP_SHARED 或 MAP_PRIVATE)。错误的标志可能导致映射失败或其他问题。
-
检查 mmap 返回值:mmap 函数在出错时返回 MAP_FAILED((void *)-1),确保在使用返回的指针之前检查是否为 MAP_FAILED。
-
忘记使用 munmap:使用完映射后,不要忘记调用 munmap 函数来解除映射。否则,可能导致资源泄漏。
-
多线程同步:如果在多线程环境中使用 mmap,确保在访问映射内存时进行适当的同步。否则,可能导致竞争条件和不一致的数据。
-
对匿名映射使用 MAP_FIXED:当需要匿名映射时,避免使用 MAP_FIXED 标志,因为这可能导致覆盖现有映射。通常可以使用 MAP_FIXED_NOREPLACE,以便在指定地址已被使用时,映射失败而不会覆盖现有映射。
注意这些易错点有助于在使用 mmap 函数时避免常见错误,从而提高代码的可靠性和稳定性。