进程映射
将磁盘文件映射到内存当中,这样进程间通信就不需要特地用到什么管道了,用普通文件速度一样快
mmap
void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset)
参数:
- addr:指定映射区的首地址,NULL表示由系统分配
- length:共享内存映射区的大小。(<=文件的实际大小)
- prot:共享内存映射区的读写属性。PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE
- flags:标注共享共享内存的共享属性。MAP_SHARED、MAP_PRIVATE
- fd:用于创建共享内存映射区的那个文件的文件描述符
- offset:偏移位置,默认0,必须是4k的整数倍
返回值:
- 成功:映射区的首地址,相当于开辟了内存空间
- 失败:(void*)-1
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.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,0644);
if(fd==-1){
sys_err("open error");
}
//拓展文件大小
ftruncate(fd,10);
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");
printf("----%s\n",p);
return 0;
}
mmap注意事项
- 用于创建映射区的文件大小为0,实际指定非0大小创建映射区,“总线错误”
- 用于创建映射区的文件大小为0,实际指定0大小创建映射区,“无效参数”
- 创建映射区首先要对磁盘文件进行读,所以文件有读权限才能创建映射区。对映射区进行写,如果映射区为共享,那么最后需要写回,需要文件的读权限。如果映射区为私有,最后不会写回,只会对映射区的内容产生影响,那么不需要文件的写权限。
- 用于创建映射区的文件读写属性为,只读。映射区属性为,读写。“无效参数”
- 文件描述符fd可以在创建完映射区后就关闭,文件描述符只是个链接而已,mmap返回的指针一样能访问。
- offset必须是4k的整数倍
- 映射区访问权限为PRIVATE,对映射区的修改只在内存上有效,不会写回
使用mmap最保险的方式
- fd = open("文件名",O_RDWR);
- mmap(NULL,有效文件大小,PROT_READ|PROT_WRITE|MAP_SHARED,fd,0);
父子进程mmap
父进程先创建映射区。open(O_RDWR),mmap(MAP_SHARED)
fork()创建子进程
一个进程写,另一个进程读
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
int var=100;
int main(){
int *p;
pid_t pid;
int fd=open("temp",O_CREAT|O_RDWR|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);
//p=(int *)mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0); //设为私有,那么fork以后,父子进程各自有一份,互不干扰
pid=fork();
if(pid<0){
perror("pid error");
exit(1);
}else if(pid==0){
*p=2000;
var=1000;
printf("child, *p=%d, var=%d\n",*p,var);
}else if(pid>0){
wait(NULL);
printf("parent, *p=%d, var=%d\n",*p,var);
close(fd);
}
}
无血缘关系进程mmap
两个进程打开同一个文件,创建映射区。你不用管实现原理,反正打开相同文件就是能映射到相同的映射区。
指定flags为MAP_SHARE
一个进程写入,一个进程读出。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
struct student{
int id;
char name[26];
int age;
};
void sys_err(const char* str){
perror(str);
exit(1);
}
int main(int argc,char* argv[]){
int fd;
struct student *p;
struct student stu={18,"xiaoming",10};
fd=open("test_map",O_CREAT|O_RDWR|O_TRUNC,0644);
if(fd==-1){
sys_err("open error");
}
ftruncate(fd,sizeof(stu));
p=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("student name=%s, id=%d, age=%d\n",p->name,p->id,p->age);
sleep(1);
}
munmap(p,sizeof(stu));
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
struct student{
int id;
char name[26];
int age;
};
void sys_err(const char* str){
perror(str);
exit(1);
}
int main(int argc,char* argv[]){
struct student stu={1,"xiaoming",18};
struct student *p;
int fd=open("test_map",O_CREAT|O_RDWR|O_TRUNC,0644);
if(fd==-1){
sys_err("open error");
}
ftruncate(fd,sizeof(stu));
p=mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(p==MAP_FAILED){
sys_err("mmap error");
}
while(1){
memcpy(p,&stu,sizeof(stu));
stu.id++;
sleep(1);
}
munmap(p,sizeof(stu));
close(fd);
}