記憶體映射的作用是使一個磁盤檔案與存儲空間的一個緩沖區建立映射關系,然後當從緩沖區中取資料,就相當于讀檔案中的相應位元組,而将資料存入緩沖區,就相當于寫檔案中的相應位元組。這樣就可以不使用read和write直接執行I/O了。參考:記憶體映射(memory map)

#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
功能:将一個檔案或者裝置的資料映射到記憶體中
參數:
-addr:記憶體中映射的首位址,一般設定為NULL,表示由核心指定
-length:要映射的資料的長度,這個值不能為0,建議使用檔案的長度(如果這個長度不是分頁的整數倍,會自動取比該長度大的分頁的整數倍)
擷取檔案的長度可以使用stat函數或者lseek函數
-prot:對申請的記憶體映射區的操作權限
- PROT_EXEC:可執行的權限
- PROT_READ:讀權限 要操作映射記憶體,必須要有讀的權限
- PROT_WRITE:寫權限
- PROT_NONE:沒有權限
-flags:
- MAP-SHARED:映射區的資料會自動和磁盤檔案進行同步,程序間通信,必須設定這個選項
- MAP-PRIVATE:不同步,記憶體映射區的資料改變了,對原來的映射區不會修改,會重新建立一個映射區
個新的映射區。(copy on write)
-fd:需要映射的那個檔案的檔案描述符,通過open得到,open的是一個磁盤檔案
注意:檔案的大小不能為0,open指定的權限不能和prot參數有沖突
prot:PROT_READ open:隻讀/讀寫
prot:PROT_READ | PROT_WRITE open:讀寫
prot的權限要小于等于open中的權限,并且prot必須有讀的權限
-offset:偏移量,一般不用。必須指定的是4K的整數倍。0表示不偏移,從檔案的開頭進行映射
傳回值:傳回建立的記憶體的首位址
失敗傳回MAP_FAILED,(void*)-1
int munmap(void *addr, size_t length);
功能:釋放記憶體映射
參數:
-addr:要釋放的記憶體的首位址
-length:要釋放的記憶體的大小,要和mmap的length值一樣。
傳回值:
成功傳回0,失敗傳回-1
使用記憶體映射實作程序間通信:
1.有關系的程序(父子程序)
還沒有子程序的時候,通過唯一的父程序,先建立記憶體映射區
有了記憶體映射區以後,建立子程序
父子程序共享建立的記憶體映射區
2.沒有關系的程序間通信
準備一個大小不是0的磁盤檔案
程序1通過磁盤檔案建立記憶體映射區,得到一個操作這塊記憶體的指針
程序2通過磁盤檔案建立記憶體映射區,得到一個操作這塊記憶體的指針
使用記憶體映射區通信
注意:記憶體映射區通信,是非阻塞的
記憶體映射實作程序間通信:是把同一個檔案映射到不同的程序中,也就是說,不同的程序共享的是檔案
共享記憶體實作程序間通信:不同的程序共享的是記憶體,程序間通信效率最高的一種方式
記憶體映射實作程序通信的示意圖:
記憶體映射需要不同的程序關聯同一個檔案,通過檔案做程序間通信
共享記憶體實作程序通信的示意圖:
1.使用記憶體映射實作父子程序間通信的執行個體:
先建立一個用于記憶體映射的檔案mmap.txt,随便輸入一些内容:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <wait.h>
int main()
{
//1.打開檔案
int fd=open("mmap.txt",O_RDWR); //以可讀可寫打開檔案
if(fd==-1)
{
perror("open");
return -1;
}
//2.得到檔案的大小
int size=lseek(fd,0,SEEK_END);
//3.進行檔案映射
void *ptr=mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(ptr==MAP_FAILED)
{
perror("mmap");
return -1;
}
//4.建立子程序
pid_t pid=fork();
if(pid==0)
{
//子程序 寫資料
char buf[1024]="hello dad!";
strcpy((char*)ptr,buf); //直接對得到的指針進行操作,省去了write 和read的調用
//write(fd,buf,strlen(buf));
}
else if(pid>0)
{
//父程序 讀資料
wait(NULL);
char buf[1024]="\0";
strcpy(buf,(char*)ptr);
//read(fd,buf,sizeof(buf));
printf("parent recv:%s\n",buf);
}
else
{
perror("fork");
return -1;
}
munmap(ptr,size); //6.釋放記憶體映射
return 0;
}
執行結果:
再次檢視mmap.txt檔案中的内容:
2.使用記憶體映射實作沒有關系的程序間通信:
建立一個用于記憶體映射的檔案mmap_2.txt:
mmap_write.c:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <wait.h>
int main()
{
int fd = open("mmap_2.txt", O_RDWR);
if (fd == -1)
{
perror("fork");
return -1;
}
int size = lseek(fd, 0, SEEK_END);
void *ptr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
{
perror("mmap");
return -1;
}
strcpy((char *)ptr, "hello,I wrote this!");
munmap(ptr, size);
return 0;
}
mmap_read.c:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <wait.h>
int main()
{
int fd = open("mmap_2.txt", O_RDWR);
if (fd == -1)
{
perror("fork");
return -1;
}
int size = lseek(fd, 0, SEEK_END);
void *ptr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
{
perror("mmap");
return -1;
}
char buf[1024] = "\0";
strcpy(buf, (char *)ptr);
printf("%s\n",buf);
munmap(ptr, size);
return 0;
}
運作之後:
再次檢視mmap_2.txt: