Linux 进程间通信 -- 文件mmap映射
2020-02-03 本文已影响0人
brownfeng
Linux 进程间通信 -- 文件mmap映射
打开一个文件, 并且指定文件中的一个区域, 映射到内存中, 然后直接操作那个内存, 就能实现进程间通信!!!因为是内存操作, 所以速度是最快的.
使用mmap进程通信速度是最快的.
函数mmap:打开一个文件,指定一个文件的区域,作为一个区域,映射到内存中,以后就直接操作那个内存,就能够实现进程间的通信。因为是内存操作,所以速度最快。
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
int munmap(void *addr, size_t length);
参数解释:
-
fd: 需要映射文件的文件描述符
-
addr:固定NULL
-
length:拿出文件中的多长的一段,映射到内存。
-
prot - PROT_READ 和 PROT_WRITE 用的多
- PROT_EXEC Pages may be executed
- PROT_READ Pages may be read.
- PROT_WRITE Pages may be written.
- PROT_NONE Pages may not be accessed
-
flags - 是否可以共享!!!
- MAP_SHARED:对内存里的值进行修改,会反映到文件,也就是文件也被修改。
- MAP_PRIVATE:对内存里的值进行修改,不会反映到文件,文件不会被修改。
-
offset:从文件内容中的哪个位置开始拿。
-
返回值
- 成功:可用的内存的首地址
- 失败:
MAP_FAILED
(that is, (void *) -1)
释放内存映射区。
#include <sys/mman.h>
int munmap(void *addr, size_t length);
- addr:mmap的返回值
- length:mmap创建的长度
- 返回值:成功0;失败-1.
简单dmeo, 需要注意mem.txt
文件需要内容长度最少大于8byte
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
// mem.txt filesize should > 8!!
int fd = open("mem.txt", O_RDWR);
// create mmap
char *mem = (char *)mmap(NULL, 8, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (mem == MAP_FAILED) {
perror("mmap err");
return -1;
}
printf("%s\n", mem);
strcpy(mem, "hello");
// release mmap
munmap(mem, 8);
close(fd);
}
使用mmap
有多个需要注意的问题:
- 创建mmap的地址和释放地址必须一致.
- 在映射区越界操作情况如下(一定要尽量避免!!!):
- open文件size > 要写入的size > mmap参数的length:能够全部写入文件。
- open文件size < 要写入的size > mmap参数的length:不能全部写入文件,能够写入的size是open文件的size
- 偏移量offset必须是4K的整数倍(0, 4 * 1024, ...), 可以用
stat
看到mmap的IO Block是4096 - 如果文件描述符先关闭, 对 mmap 映射没有影响
- open的时候,可以用新创建一个文件的方式,来创建映射区吗? 会导致
Bus error(core dumped)
, 创建的文件的size为0,所以出上面的错误。新创建一个文件后,马上把文件大小扩展一下就不会发生错误了。int fd = open("mem", O_RDWR|O_CREAT, 0666);
ftruncate(fd, 8);
//把新创建的文件mem的大小扩展为8. - open文件时,选择
O_WRONLY
时候,mmap
函数出错,错误Permission denied
, 因为要把文件的内容读到内存,所以隐含一次读取操作,所以没有读的权限的话,就出这个错误。 - 当选择
MAP_SHARED
的时候,open文件选择O_RDONLY
,prot
不能是PROT_READ|PROT_WRITE
, 会导致mmap
函数出错,错误Permission denied
,MAP_SHARED
的时候会去写文件,但是open的时候只有读权限,所以权限不够。
用mmap实现父子进程间通信的例子:
参数flags必须是
MAP_SHARED
,因为2个进程间通信,需要互相读写,所以必须是MAP_SHARED
, 并且我们使用open
+ftruncate
的组合, 重新创建一个文件.
#include <fcntl.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
int fd = open("mem.txt", O_RDWR | O_CREAT);
ftruncate(fd, 4);
int *mem = (int *)mmap(NULL, 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (mem == MAP_FAILED) {
perror("mmap");
return -1;
}
pid_t pid = fork();
if (pid == 0) {
*mem = 100;
printf("child:mem=%d\n", *mem);
sleep(3);
printf("child:mem=%d\n", *mem);
} else if (pid > 0) {
sleep(1);
printf("parent:mem=%d\n", *mem);
*mem = 200;
printf("parent:mem=%d\n", *mem);
wait(NULL);
}
munmap(mem, 4);
close(fd);
}
从这个实例看到, 必须要先打开文件, 再使用mmap
创建内存映射区(同时使用MAP_SHARRED
), 比较麻烦, Linux也提供另外一种内存映射 -- 匿名映射