共享内存:共享内存区是最快的IPC形式,一旦这样的内存映射到共享的进程的地址空间,这些进程间数据的传递
不再涉及到内核,换句话说就是进程不再通过执行进入内核的系统调用来传递彼此的数据
共享内存就是映射一段能被其他进程所访问的内存,这段内存由一个进程创建,但多个进程都可以访问。
管道或者消息队列会有多次系统调用陷入内核,效率远不如共享内存。
void *mmap(void *addr,size_t len,int prot,int flags,int fd,off_t offset);
功能:将文件或者设备映射到共享内存区,对内存的操作就像是对文件操作,成功返回映射到的内存区的起始地址。
addr:要映射的文件应被映射到的进程地址空间起始地址,通常指定为NULL,让内核自己选择
len:映射到进程地址空间的字节数
prot:映射区保护方式 PROT_READ:映射的页面可读、PROT_WRITE:页面可写、PROT_EXEC:页面可执行、PROT_NONE:页面不可访问
flags:标志 MAP_SHARED:变动是共享的、MAP_PRIVATE:变动是私有的、MAP_FIXED:准确解释addr参数、MAP_ANONYMOUS:匿名映射区
fd:文件描述符
offset:从文件头开始的偏移量
#include<unistd.h> #include<sys/types.h> #include<sys/socket.h> #include<string.h> #include<stdlib.h> #include<stdio.h> #include<errno.h> #include<sys/un.h> #include<fcntl.h> #include<sys/mman.h> #define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); }while(0) typedef struct stu { char name[4]; int age; }STU; int main(int argc,char *argv[]) { if(argc!=2) { fprintf(stderr,"Usage:%s <file> ",argv[0]); exit(EXIT_FAILURE); } int fd; //打开传递进来的文件 fd=open(argv[1],O_CREAT|O_RDWR|O_TRUNC,0666); if(fd==-1) ERR_EXIT("open"); //重定位光标到39字节处 lseek(fd,sizeof(STU)*5-1,SEEK_SET); //写入1个空字符 write(fd,"",1);//od -c test:查看二进制文件 STU * p;//返回共享内存区首地址 //将上面的文件映射到共享内存区,内存区页面可读、可写 p=(STU*)mmap(NULL,sizeof(STU)*5,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);//以页面为单位来创建共享内存区 if(p==NULL) ERR_EXIT("mmap"); char ch='a'; //写共享内存相当于写文件 int i; for(i=0;i<5;i++) { memcpy((p+i)->name,&ch,1);//5个学生的信息,ch拷贝到内存中 (p+i)->age=20+i; ch++; } printf("initialize over "); close(fd); munmap(p,sizeof(STU)*5); printf("exit... "); return 0; }
mmap注意点
1、映射不能改变文件大小
2、可用于进程间通信的有效地址空间不完全受限于被映射文件的大小
3、文件一旦被映射后,所有对映射区域的访问实际上是对内存区域的访问。映射区域内容写回文件时,所写内容不能超过文件大小
下面这个程序用于读取共享内存区,都到一个文件中,这个共享内存区的内容是由上面的程序将text文件映射到此内存区的内容。
#include<unistd.h> #include<sys/types.h> #include<sys/socket.h> #include<string.h> #include<stdlib.h> #include<stdio.h> #include<errno.h> #include<sys/un.h> #include<fcntl.h> #include<sys/mman.h> #define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); }while(0) typedef struct stu { char name[4]; int age; }STU; int main(int argc,char *argv[]) { if(argc!=2) { fprintf(stderr,"Usage:%s <file> ",argv[0]); exit(EXIT_FAILURE); } int fd; fd=open(argv[1],O_RDWR); if(fd==-1) ERR_EXIT("open"); STU * p; p=(STU*)mmap(NULL,sizeof(STU)*5,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); int i; //此时读取共享内存区相当于读取文件 for(i=0;i<5;i++) { printf("name=%s age=%d ",(p+i)->name,(p+i)->age); } close(fd); munmap(p,sizeof(STU)*5); return 0; }