目录
- mmap函数
- 1.函数原型
- 2.建立映射区
- 3.注意事项
- 4.父子进程间mmap通信
- 4.无血缘关系进程间mmap通信
- 写进程:
- 读进程:
- 附:文件用于进程间通信
mmap函数
1.函数原型
- void *mmap(void *addr,size_t length, int prot,int flags, int fd,off_t
offset);
创建共享内存映射
参数:
- addr:指定映射区的首地址。通常传NULL,表示让系统自动分配
- length:共享内存映射区的大小
- prot:共享内存映射区的读写属性。PROT_READ、PROT_YRITE、PROT_READ、PROT__RITE
- flags:标注共享内存的共享属性。MAP_SHARED、IAP_PRIVATE
- fd:用于创建共亨内存映射区的那个文件的文件描述符。
- offset:偏移位置。需是4的整数倍。
返回值:
- 成功:映射区的首地址。
- 失败:MAP_FAILED , errno
2.建立映射区
- int manmap(void *addr,size_t length);
释放映射区。 - addr: mmap的返回值
- length:大小
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/mman.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
void sys_err(const char *str)
{
perror(str);
exit(1);
}
int main(int argc,char *argv[])
{
char *p = NULL;
int fd;
fd = open("testmap",O_RDWR|O_CREAT|O_TRUNC,0664);
if(fd == -1)
{
sys_err("open error");
}
/*
lseek(fd,10,SEEK_END);
write(fd,"\0",1);
*/
ftruncate(fd,20);
int len = lseek(fd,0,SEEK_END);
p = mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(p == MAP_FAILED)
{
sys_err("mmap error");
}
//使用p对文件进行读写操作
strcpy(p,"hello mmap");
printf("-----%s\n",p);
int ret = munmap(p,len);
if(ret == -1)
{
sys_err("munmap error");
}
return 0;
}
3.注意事项
- 1.用于创建映射区的文件大小为0,实际指定非0大小创建映射区,出“总线错误”。
- 2.用于创建映射区的文件大小为0,实际制定0大小创建映射区,出“无效参数”。
- 3.用于创建映射区的文件读写属性为,只读。映射区属性为读、写。出“无效参数”。
- 4.创建映射区,需要read权限。当访问权限指定为“共享”MAP_SHARED是, mmap的读写权限,应该<=文件的open权限。只写不行。
- 5.文件描述符fd,在mmap创建映射区完成即可关闭。后续访问文件,用地址访间。
- 6.offset 必须是4096的整数倍。(MMU映射的最小单位4 )
- 7.对申请的映射区内存,不能越界访问。
- 8.munmap用于释放的地址,必须是mmap申请返回的地址。
- 9.映射区访问权限为“私有”MAP_PRIVATE,对内存所做的所有修改,只在内存有效,不会反应到物理磁盘上。
- 10.映射区访问权限为“私有”MAP_PRIVATE,只需要open文件时,有读权限,用于创建映射区即可。
4.父子进程间mmap通信
- 父进程先创建映射区。open ( O_RDWR)map( MAP_SHARED ) ;
- 指定MAP_SHARED权限
- fork()创建子进程。
- 一个进程读,另外一个进程写。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/mman.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
int var = 200;
void sys_err(const char *str)
{
perror(str);
exit(1);
}
int main(int argc,char *argv[])
{
int *p;
pid_t = pid;
int fd;
fd = open("testmap",O_RDWR|O_CREAT|O_TRUNC,0664);
if(fd == -1)
{
sys_err("open error");
}
ftruncate(fd,20);
p = (int *)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(p == MAP_FAILED)
{
sys_err("mmap error");
}
close(fd); //映射区创建完毕,即可关闭文件
pid = fork(); //创建子进程
if(pid == 0){
*p = 2000; //写共享内存
var = 1000;
}else{ //父进程操作
sleep(1);
printf("parent,*p = %d,var = %d\n",*p,var);//读共享内存,var:读时共享,写时复制
wait(NULL);
int ret = munmap(p,len);//释放映射区
if(ret == -1)
{
sys_err("munmap error");
}
}
return 0;
}
4.无血缘关系进程间mmap通信
- 两个进程打开同一个文件,创建映射区。
- 指定f1ags 为 MAP_SHARED。
- 一个进程写入,另外一个进程读出。
【注意】﹔无血缘关系进程间通信。
- mmap:数据可以重复读取。
- fifo:数据只能一次读取。
写进程:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/mman.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
struct student{
int id;
char name[25];
int age;
};
void sys_err(const char *str)
{
perror(str);
exit(1);
}
int main(int argc,char *argv[])
{
struct student stu = {110,"xiaom",18};
struct student *p;
int fd;
fd = open("testmap",O_RDWR|O_CREAT|O_TRUNC,0664);
if(fd == -1)
{
sys_err("open error");
}
ftruncate(fd,sizeof(stu));
p = (struct student *)mmap(NULL,sizeof(stu),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(p == MAP_FAILED)
{
sys_err("mmap error");
}
close(fd); //映射区创建完毕,即可关闭文件
while(1){
memcpy(p,&stu,sizeof(stu));
stu.id++;
sleep(1);
}
munmap(p,sizeof(stu));
return 0;
}
读进程:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/mman.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
struct student{
int id;
char name[25];
int age;
};
void sys_err(const char *str)
{
perror(str);
exit(1);
}
int main(int argc,char *argv[])
{
struct student stu;
struct student *p;
int fd;
fd = open("testmap",O_RDWR|O_CREAT|O_TRUNC,0664);
if(fd == -1)
{
sys_err("open error");
}
p = (struct student *)mmap(NULL,sizeof(stu),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(p == MAP_FAILED)
{
sys_err("mmap error");
}
close(fd); //映射区创建完毕,即可关闭文件
while(1){
printf("id = %d,name = %s,age = %d",p->id,p->name,p->age);
sleep(1);
}
munmap(p,sizeof(stu));
return 0;
}
附:文件用于进程间通信
一个进程对文件读,另一进程对文件写