共享内存:是最快的IPC形式,一旦这样的内存映射到共享它的进程的地址空间,这些进程间的数据传递不再涉及到内核,不用通过执行进入内核的系统调用来传递彼此的数据。
mmap函数:
功能:将文件或者设备空间映射到共享内存区。
void*mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
参数
addr:要映射的起始地址,通常指定为NULL,让内核自动选择
len:映射到进程地址空间的字节数
prot:映射区保护方式
flags:标志
fd:文件描述符
offset:从文件头开始的偏移量
返回值:成功返回映射到的内存区的起始地址;失败返回-1
munmap函数:
功能:取消mmap函数建立的映射
int munmap(void *addr, size_t len);
参数
addr:映射的内存起始地址
len:映射到进程地址空间的字节数
返回值:成功返回0;失败返回-1
msync函数:
功能:对映射的共享内存执行同步操作(立刻写回文件)
int msync(void *addr, size_t len, int flags);
参数
addr:内存起始地址
len:长度
flags:选项
返回值:成功返回0;失败返回-1
使用示例:
write:
#include<unistd.h>//read/write
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.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>\n",argv[0]);
exit(EXIT_FAILURE);
}
int fd;
fd = open(argv[1],O_CREAT | O_RDWR | O_TRUNC, 0666);
if(fd == -1)
ERR_EXIT("open");
lseek(fd,sizeof(STU)*5-1,SEEK_SET);
write(fd,"",1);
//以上创建了文件,接下来进行文件映射
STU *p;
//但应注意:映射不能改变文件大小,但可以通过映射传递大于文件大小的内容
p = (STU*)mmap(NULL,sizeof(STU)*10,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
if(p == NULL)
ERR_EXIT("mmap");
//映射成功,写入操作
char ch = 'a';
int i;
for(i = 0;i<10;i++)
{//对文件的访问就是对内存的访问
memcpy((p+i)->name,&ch,1);
(p+i)->age = 20+i;
ch++;
}
printf("initialize over\n");
sleep(10);
munmap(p,sizeof(STU)*10);
printf("exit...\n");
return 0;
}
read:
#include<unistd.h>//read/write
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.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>\n",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)*10,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
if(p == NULL)
ERR_EXIT("mmap");
//映射成功,读取操作
int i;
for(i = 0;i<10;i++)
{//对文件的访问就是对内存的访问
printf("name = %s,age = %d\n",(p+i)->name,(p+i)->age);
}
munmap(p,sizeof(STU)*10);
printf("exit...\n");
return 0;
}
共享内存映射注意点:
- 映射不能改变文件的大小;
- 可用于进程间通信的有效地址空间不完全受限于被映射文件的大小;(映射的时候是根据页面大小来的)
- 文件一旦被映射后,所有对映射区域的访问实际上是对内存区域的访问。映射区域内容写回文件时,所写内容不能超过文件的大小。
共享内存进一步使用: