共享內存:是最快的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;
}
共享內存映射注意點:
- 映射不能改變文件的大小;
- 可用於進程間通信的有效地址空間不完全受限於被映射文件的大小;(映射的時候是根據頁面大小來的)
- 文件一旦被映射後,所有對映射區域的訪問實際上是對內存區域的訪問。映射區域內容寫回文件時,所寫內容不能超過文件的大小。
共享內存進一步使用: