面试题答案
一键面试mmap函数主要参数及其作用
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
addr
:- 作用:指定映射区的起始地址,通常设为
NULL
,让内核自动选择合适的地址。如果不为NULL
,则必须是页对齐的地址,并且在指定了MAP_FIXED
标志时,内核将按照指定地址进行映射。
- 作用:指定映射区的起始地址,通常设为
length
:- 作用:指定映射区的长度,单位是字节。这个长度必须是系统页大小(通常是4096字节)的整数倍。
prot
:- 作用:指定映射区的保护方式。常用值有:
PROT_READ
:映射区可读。PROT_WRITE
:映射区可写。PROT_EXEC
:映射区可执行。PROT_NONE
:映射区不可访问。
- 作用:指定映射区的保护方式。常用值有:
flags
:- 作用:指定映射的类型和其他选项。常用值有:
MAP_SHARED
:共享映射,对映射区的修改会反映到文件中,同时其他进程对该文件的映射也能看到这些修改。MAP_PRIVATE
:私有映射,对映射区的修改不会反映到文件中,而是产生一个写时复制(copy - on - write)的副本。MAP_FIXED
:使用指定的addr
地址进行映射,如果addr
地址不合适,映射将失败。通常不建议使用,除非对内存布局非常清楚。
- 作用:指定映射的类型和其他选项。常用值有:
fd
:- 作用:要映射的文件描述符,通过
open
函数打开文件获得。
- 作用:要映射的文件描述符,通过
offset
:- 作用:文件映射的偏移量,必须是系统页大小的整数倍。通常设为0,表示从文件开头开始映射。
基本代码框架
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
int main() {
int fd;
struct stat sb;
char *p;
// 打开文件
fd = open("test.txt", O_RDWR);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
// 获取文件状态
if (fstat(fd, &sb) == -1) {
perror("fstat");
close(fd);
exit(EXIT_FAILURE);
}
// 内存映射
p = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (p == MAP_FAILED) {
perror("mmap");
close(fd);
exit(EXIT_FAILURE);
}
// 对映射内存进行读写操作示例
strcpy(p, "Hello, mmap!");
// 解除映射
if (munmap(p, sb.st_size) == -1) {
perror("munmap");
close(fd);
exit(EXIT_FAILURE);
}
// 关闭文件
if (close(fd) == -1) {
perror("close");
exit(EXIT_FAILURE);
}
return 0;
}
映射后内存数据与文件的同步问题
- 使用
msync
函数:- 在使用
MAP_SHARED
映射时,如果需要确保映射内存中的数据被写回到文件,可以使用msync
函数。其原型为int msync(void *addr, size_t length, int flags);
。 - 参数:
addr
:映射内存区的起始地址,即mmap
返回的地址。length
:要同步的内存区长度。flags
:常用标志有MS_SYNC
(同步写回,等待写操作完成)、MS_ASYNC
(异步写回,不等待写操作完成)、MS_INVALIDATE
(使其他进程对该映射的缓存失效)。
- 例如,在上述代码对映射内存进行写操作后,要将数据同步到文件,可以在
munmap
之前添加:
- 在使用
if (msync(p, sb.st_size, MS_SYNC) == -1) {
perror("msync");
exit(EXIT_FAILURE);
}
- 解除映射时:
- 当调用
munmap
解除映射时,如果映射类型是MAP_SHARED
,系统通常会自动将映射内存中修改的数据写回到文件,但为了确保数据一致性,建议在munmap
之前显式调用msync
进行同步。
- 当调用