共享内存区是最快的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
prot |
说明 |
PROT_READ |
页面可读 |
PROT_WRITE |
页面可写 |
PROC_EXEC |
页面可执行 |
PROT_NONE |
页面不可访问 |
flags |
说明 |
MAP_SHARED |
变动是共享的 |
MAP_PRIVATE |
变动是私有的 |
MAP_FIXED |
准确解释addr参数 |
MAP_ANONYMOUS |
建立匿名映射区,不涉及文件 |
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
flags |
说明 |
MS_ASYNC |
执行异步写 |
MS_SYNC |
执行同步写 |
MS_INVALIDATE |
使高速缓存的数据失效 |
map注意点
映射不能改变文件的大小
可用于进程间通信的有效地址空间不完全受限于被映射文件的大小
文件一旦被映射后,所有对映射区域的访问实际上是对内存区域的访问。映射区域内容写回文件时,所写内容不能超过文件的大小。
nmap_read.c
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.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)*5, 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;
}
nmap_write.c
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.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;
}
makefile:
.PHONY:clean all
CC=gcc
CFLAGS=-Wall -g
BIN=mmap_write mmap_read
all:$(BIN)
%.o:%.c
$(CC) $(CFLAGS) -c $< -o [email protected]
clean:
rm -f *.o $(BIN)
共享内存区