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#include#include#include#include#include
intmain()
{intlen,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#include#include#include#include#include
int var = 100;intmain()
{int *p;
pid_t pid;intfd;
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#include#include#include#include#include
int var = 100;intmain()
{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#include#include#include#include#include
int var = 100;intmain()
{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#include#include#include#include#include#include
structSTU
{intid;char name[20];charsex;
};void sys_err(char *str)
{
perror(str);
exit(1);
}int main(int argc,char **argv)
{intfd;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#include#include#include#include#include#include
structSTU
{intid;char name[20];charsex;
};void sys_err(char *str)
{
perror(str);
exit(1);
}int main(int argc,char **argv)
{intfd;structSTU 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;
}