mmap()函數:
void *mmap(void* addr,size_t length,int port,int flags,int fd,off_t offset);
返回:成功:返回創建的映射區首地址;失敗:MAP_FAILED 宏
參數:
?????? addr:????? 建立映射區的首地址,由linux內核決定。使用時直接傳遞NULL;
?????? length:?? 欲創建映射區的大小
?????? port:??? 映射區權限PROT _READ、PROT_WRITE 、PROT _READ|PROTWRITE
?????? flags:?? 標志位參數(常用于設定更新物理區域、設置共享、創建匿名映射區)
???????????????????? MAP_SHARED:???? 會將映射區所做的操作反射到物理設備上
???????????????????? MAP_PRIVATE:???? 映射區所作的修改不會反映到物理設備。
?????? fd:?????? 用來建立映射區的文件描述符
?????? offset:? 映射文件的偏移(4K的整數倍)
/*** mmap.c ***/ #include<stdio.h> #include<fcntl.h> #include<unistd.h> #include<string.h> #include<stdlib.h> #include<sys/mman.h>int main() {int len,ret;char *p = NULL;int fd = open("mytest.txt",O_CREAT|O_RDWR,0644);if(fd < 0 ){perror("open error:");exit(1);}len = ftruncate(fd,4);if(-1 == len){perror("ftruncate error:");exit(1);}p = mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(p == MAP_FAILED){perror("mmap error:");exit(1);}strcpy(p,"abc");ret = munmap(p,4);if(-1 == ret){perror("mmap error:");exit(1);} close(fd);return 0; }
運行結果:
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ gcc mmap.c -o mmap
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ ./mmap
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ cat mytest.txt
abc
mmap在使用過程中注意以下事項:
- 創建映射區的過程中,隱含著一次對映射文件的讀操作。
- 當MAP_SHARED時,要求:映射區的權限? <= 文件打開的權限(出于對映射區的保護)。而MAP_PRIVATE則無所謂,因為mmap中的權限時對內存的限制。
- 映射區的釋放和文件關閉無關。只要映射成功,文件可以立刻關閉。
- 特別注意:當映射文件大小為0時,不能創建映射區。所以:用于映射的文件必須有實際大小。mmap使用時常常會出現總線錯誤,通常是因為共享文件存儲空間大小所引起的。
- munmap傳入的地址一定是mmap的返回地址,堅決杜絕指針++操作
- 如果使用文件偏移,則值必須是4K的整數倍
- mmap創建映射區出錯概率極高,一定要檢查返回值,確保映射區建立成功再進行后續操作。
?
mmap父子進程間通信:
文件inode屬性
struct stat
{
?????? 存儲指針地址;
?????? 大小;
?????? 權限;
?????? 類型;
?????? 所以者;
}
/*** mmap_fork.c ***/ #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<fcntl.h> #include<sys/mman.h> #include<sys/wait.h>int var = 100;int main() {int *p;pid_t pid;int fd;fd = open("temp",O_RDWR|O_CREAT|O_TRUNC,0644);if(fd < 0){perror("open error");exit(1);}unlink("temp");ftruncate(fd,4);p = (int*)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(p == MAP_FAILED){perror("mmap error");exit(1);}close(fd);pid = fork();if(0 == pid){*p = 2000;var = 1000;printf("child, *p = %d, var = %d\n",*p,var);}else{sleep(1);printf("parent, *p = %d, var = %d\n",*p,var);wait(NULL);int ret = munmap(p,4);if(-1 == ret){perror("munmap error");exit(1);}}return 0; }
運行結果:
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ gcc mmap_fork.c -o mmap_fork
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ ./mmap_fork
child, *p = 2000, var = 1000
parent, *p = 2000, var = 100
?
mmap創建匿名映射區
/*** fork_mmap_linux.c ***/ #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<fcntl.h> #include<sys/mman.h> #include<sys/wait.h>int var = 100;int main() {int *p;pid_t pid;p = (int*)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED | MAP_ANON,-1,0);if(p == MAP_FAILED){perror("mmap error");exit(1);}pid = fork();if(0 == pid){var = 1000;*p = 2000;printf("child, *p = %d,var = %d\n",*p,var);}else{sleep(1);// printf("parent,*p = %d\n",*p);printf("child, *p = %d,var = %d\n",*p,var);wait(NULL);int ret = munmap(p,4);if(-1 == ret){perror("munmap error");exit(1);}}return 0; }
運行結果:
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ gcc fork_map_linux.c -o fork_map_linux
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ ./fork_map_linux
child, *p = 2000,var = 1000
child, *p = 2000,var = 100
?
注意:MAP_ANONYMOUS和MAP_ANON 這兩個宏是linux操作系統特有的宏,再類Unix系統中如無該宏的定義,可以使用以下步驟來完成匿名映射區的建立。
- fd = open(“/dev/zero”,O_RDWR);
- p = mmap(NULL,size,PROT_READ|PROT_WRITE,MMAP_SHARED,fd,0);
/*** fork_map_anon.c ***/ #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<fcntl.h> #include<sys/mman.h> #include<sys/wait.h>int var = 100;int main() {int *p;pid_t pid;int fd = open("/dev/zero",O_RDWR);p = (int*)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(p == MAP_FAILED){perror("mmap error");exit(1);}pid = fork();if(0 == pid){var = 1000;*p = 2000;printf("child, *p = %d,var = %d\n",*p,var);}else{sleep(1);// printf("parent,*p = %d\n",*p);printf("child, *p = %d,var = %d\n",*p,var);wait(NULL);int ret = munmap(p,4);if(-1 == ret){perror("munmap error");exit(1);}}return 0; }
運行結果:
buntu1604@ubuntu:~/wangqinghe/linux/20190807$ gcc fork_map.c -o fork_map
ubuntu1604@ubuntu:~/wangqinghe/linux/20190807$ ./fork_map
child, *p = 2000,var = 1000
child, *p = 2000,var = 100
?
mmap無血緣關系進程間通信:
/*** mmap_w.c ***/ #include<stdio.h> #include<sys/stat.h> #include<fcntl.h> #include<unistd.h> #include<stdlib.h> #include<sys/mman.h> #include<string.h>struct STU {int id;char name[20];char sex; };void sys_err(char *str) {perror(str);exit(1); }int main(int argc,char ** argv) {int fd;struct STU student = {10,"xiaoming",'m'};char *mm;if(argc < 2){printf("./a.out file_shared\n");exit(-1);}fd = open(argv[1],O_RDWR | O_CREAT,0664);ftruncate(fd,sizeof(student));mm = mmap(NULL,sizeof(student),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(mm == MAP_FAILED){sys_err("mmap error");}close(fd);while(1){memcpy(mm,&student,sizeof(student));student.id++;sleep(2);}munmap(mm,sizeof(student));return 0; }
/*** mmap_r.c ***/ #include<stdio.h> #include<sys/stat.h> #include<fcntl.h> #include<unistd.h> #include<stdlib.h> #include<sys/mman.h> #include<string.h>struct STU {int id;char name[20];char sex; };void sys_err(char *str) {perror(str);exit(1); }int main(int argc,char ** argv) {int fd;struct STU student;struct STU *mm;if(argc < 2){printf("./a.out file_shared\n");exit(-1);}fd = open(argv[1],O_RDONLY);if(-1 == fd)sys_err("open error");mm = mmap(NULL,sizeof(student),PROT_READ,MAP_SHARED,fd,0);if(mm == MAP_FAILED){sys_err("mmap error");}close(fd);while(1){printf("id=%d,name = %s,%c\n",mm->id,mm->name,mm->sex);sleep(2);}munmap(mm,sizeof(student));return 0; }
?