柳玉祥,王亦丰整容,素描石膏像
创建内存映射区。
#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);
函数mmap:打开一个文件,指定一个文件的区域,作为一个区域,映射到内存中,以后就直接操作那个内存,就能够实现进程间的通信。因为是内存操作,所以速度最快。
释放内存映射区。
#include <sys/mman.h> int munmap(void *addr, size_t length);
例子:
#include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <unistd.h> int main(){ int fd = open("mem", o_rdwr); //char* buf = mmap(null, 8, prot_read|prot_write, map_shared, fd, 0); char* buf = mmap(null, 8, prot_read|prot_write, map_private, fd, 0); printf("%s\n", buf); strcpy(buf, "fffff"); //释放映射区 munmap(buf, 8); close(fd); }
mmap的七个问题:
如果更改上面例子里变量buf的地址,释放的时候munmap,还能成功吗?
不能成功。错误信息:【invalid argument】
对映射区的操作,越界了会怎么样。
偏移量随便填个数字会怎么样。
mmap函数出错,错误信息:【invalid argument】
offset必须是4k的整数倍,【0,4*1024。。。】
用【stat】命令查看文件,发现文件的size实际小于4096,但是【io block: 4096】
file: pi2.c size: 442 blocks: 8 io block: 4096 regular file device: 801h/2049d inode: 424247 links: 1 access: (0664/-rw-rw-r--) uid: ( 1000/ ys) gid: ( 1000/ ys) access: 2019-05-02 12:54:13.812282158 +0800 modify: 2019-04-29 13:49:42.489004001 +0800 change: 2019-04-29 13:49:42.489004001 +0800
如果文件描述符先关闭,对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
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/wait.h> int main(){ int fd = open("mem", o_rdwr); int* mem = 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); }
执行结果:
child:mem=100 parent:mem=100 parent:mem=200 child:mem=200
不知道读者同学们发现了没有,用mmap有个非常鸡肋的地方,就是必须要使用一个文件,其实这个文件对程序没有什么作业。所以linux给我们提供了一个方法,叫做【匿名映射】。
匿名映射:在调用mmap函数时候,在flags参数那里,设置【map_anon】,并在fd参数那里设置【-1】。
int* mem = mmap(null, 4, prot_read | prot_write, map_shared|map_anon, -1, 0);
有个问题,在有些unix系统里是没有【map_anon】【map_anonymous】这2个宏的,这2个宏的作用是一样的,其中一个是简写。那怎么办呢?
使用下面2个文件去映射,因为要用文件,所以必须还得有open的调用,但好处是不用事先做出一个大小合适的文件了。
匿名映射的弱点:不能实现无学员关系进程间的通信。
用mmap实现无血缘关系的进程间通信的例子:
写入端:
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/wait.h> typedef struct _student{ int id; char name[20]; }student; int main(int argc, char* argv[]){ int fd = open("aaa", o_rdwr|o_trunc|o_creat, 0666); int length = sizeof(student); ftruncate(fd, length); student* std = mmap(null, length, prot_read | prot_write, map_shared, fd, 0); if(std == map_failed){ perror("mmap"); return -1; } int num = 0; while(1){ std->id = num; sprintf(std->name, "xiaoming-%03d", num++); sleep(1); } munmap(std, length); close(fd); }
读入端:
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/wait.h> typedef struct _student{ int id; char name[20]; }student; int main(int argc, char* argv[]){ int fd = open("aaa", o_rdwr); int length = sizeof(student); student* std = mmap(null, length, prot_read | prot_write, map_shared, fd, 0); if(std == map_failed){ perror("mmap"); return -1; } while(1){ printf("id:%03d, name:%s\n", std->id, std->name); sleep(1); } munmap(std, length); close(fd); }
利用mmap实现用多个进程拷贝一个文件的例子(代码还没写完)
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/wait.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <sys/mman.h> //argv[1]:process count //argv[2]:src file int main(int argc, char* argv[]){ if(argc < 3){ printf("bad argv,need 3 arg"); return -1; } struct stat sbuf; int ret = stat(argv[2], &sbuf); if(ret < 0){ perror("stat"); return -1; } off_t sz = sbuf.st_size; off_t yu = sz % atoi(argv[1]); off_t prosz = (sz - yu) / atoi(argv[1]); printf("prosz:%ld, yu:%ld\n", prosz, yu); //open src file int srcfd = open(argv[2], o_rdonly); //create target file char wk[20] = {0}; sprintf(wk, "%s.copy", argv[2]); int decfd = open(wk,o_rdwr|o_creat|o_trunc, 0666); ret = ftruncate(decfd, sz); if(ret < 0){ perror("ftruncate"); return -1; } void* vc[atoi(argv[1])]; for(int i = 0; i < atoi(argv[1]); ++i){ vc[i] = mmap(null, prosz, prot_read|prot_write, map_shared, decfd, 0); if(vc[i] == map_failed){ perror("mmap die:"); return -1; } } close(srcfd); close(decfd); }
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
网友评论