- 内存映射区:将磁盘上的数据映射到内存上,于是可以不通过io文件,而是操作内存即可操作文件
1. 创建内存映射区 -- mmap函数
void *mmap(void *addr, //映射区首地址,传NULL,由系统自动识别
size_t length, //映射区的大小,一般为文件的大小(实际上分配的是4K的整数倍),不能为0
int prot, //映射区的权限:PROT_EXEC,PROT_READ<必须要有>,PROT_WRITE,PROT_NONE
int flags, //MAP_SHARED || MAP_PRIVATE
// shared会修改了内存数据将同步到磁盘,private则不会
int fd, //需要映射到内存区的文件操作符,通过open函数得到
off_t offset //映射文件时的偏移量,即从文件中的某处开始映射,必须为4K(4096)的整数倍或0
);
2. 返回值:
a. 调用成功:返回指针,指向内存映射区的首地址
b. 调用失败:返回MAP_FAILED <即(void *) -1>
- 释放内存映射区:munmap函数
1. 函数原型:
int munmap(void *addr, size_t length);
2. 参数:
addr:内存映射区首地址,即mmap的返回值
length:释放映射区大小,即mmap的第二个参数
3. 返回值:
-1:函数调用失败,一般为参数错误
0:函数调用成功
- mmap注意事项
1. 不能队mmap函数的返回值指针进行++或--等操作,否则munmap函数将无法释放内存映射区
2. open文件指定的权限需要大于等于mmap函数prot的权限<read/write>
3. mmap函数offset参数必须是4096的整数倍或0
4. mmap函数的length参数不能小于等于0
5. mmap函数的prot参数必须带有READ
6. mmap函数后关闭原来的fd,队mmap映射区没有影响
7. 对ptr指针进行越界操作时,如果原本内存被占用,则产生段错误。即在内存映射区中的内容才可以同步到文件中去
- 有血缘关系的进程间通信<非阻塞>
1. 父子进程间永远共享:
a. 文件描述符
b. 内存映射区
2. 父进程在创建内存映射区后,创建子进程,父子进程都是通过mmap返回值ptr进行操作
3. 不再使用read/write进行文件io操作,直接操作内存
4. 数据直接在内存中交换,效率高,但是不是阻塞的。
- 仅有血缘关系进程间通信:匿名映射区<非阻塞>
1. 创建时不再传入打开文件的fd
a. 首先指定内存映射区大小
int len = 4096;
b. 调用mmap函数
void *ptr = mmap(NULL, len, PROT_READ | PROT_WRIET, MAP_SHARED | MAP_ANON, -1, 0);
在映射区flag中添上MAP_ANON表明匿名内存映射区,fd位置传入-1
2. 释放内存映射区时
munmap(ptr, len);//同样使用之前的参数
- 无血缘关系进程间通信:只能通过磁盘文件创建内存映射区<非阻塞>
1. 打开的磁盘文件作为两个无血缘关系进程建立了桥梁
2. 例如:进程A(a.c)和进程B(b.c)
<1>. a.c文件
int fd = open("file.txt");
void *ptr = mmap(...,fd,0);
对ptr进行读写操作
<2>. b.c文件
int fd1 = open("file.txt");
void *ptr1 = mmap(...,fd1,0);
对ptr1进行读写操作
3. 在对ptr指针进行读写操作时,不应直接对ptr进行操作,而是复制其指针位置,然后对复制的指针进行操作
char *p = (char *)ptr;
p = p + 1024;
strcpy(p,"hello world!\n");//写操作
//或者读操作
print("%s", (char *)p);