程序間通信-記憶體共享映射
程序間通信-記憶體共享映射
一、簡述
-
系統調用使得程序之間通過映射同一個普通檔案實作mmap()
。普通檔案被映射到共享記憶體
後,程序可以向通路普通記憶體一樣對檔案進行通路,不必再調用read(),write()等操作。程序位址空間
-
的作用是映射檔案描述符fd指定檔案的mmap()
區域至調用程序的[off,off + len]
的記憶體區域, 如下圖所示:[addr, addr + len]
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL1MGRNJTWq10MNpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLxQTMxMTMyIjM1ATNwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
二、mmap 函數
功能:
mmap() 可以把磁盤檔案的一部分直接映射到記憶體,這樣檔案中的位置直接就有對應的記憶體
位址,對檔案的讀寫可以直接用指針來做而不需要read/write函數。
頭檔案:
#include <sys/mman.h>
函數原型:
void* mmap ( void * addr , size_t len , int prot ,
int flags , int fd , off_t offset )
參數說明:
-
:指定檔案應被映射到程序空間的起始位址,一般被指定一個空指針,此時選擇起始位址的任務留給核心來完成。addr
-
:是映射到調用程序位址空間的位元組數,它從被映射檔案開頭offset個位元組開始算起。len
-
:指定空想記憶體的通路權限。可取如下幾個值的或:PROT_READ(可讀)、PROT_WRITE(可寫)、PROT_EXEC(可執行)、PROT_NONE(不可通路)。prot
-
:由以下幾個常值指定:MAP_SHARED、MAP_PRIVATE、MAP_FIXED,其中,MAP_SHARED,MAP_PRIVATE必選其一,而MAP_FIXED則不推薦使用。flag
-
MAP_SHARED:多個程序對同一個檔案的映射是共享的,一個程序對映射的記憶體做了修
改,另一個程序也會看到這種變化。
-
MAP_PRIVATE:多個程序對同一個檔案的映射不是共享的,一個程序對映射的記憶體做了修
改,另一個程序并不會看到這種變化,也不會真的寫到檔案中去。
-
-
:為即将映射到程序空間的檔案描述字,一般由open()傳回,同時,fd可以指定為-1,此時須指定flags參數中的MAP_ANON,表明進行的是匿名映射(不涉及具體的檔案名,避免了檔案的建立及打開,很顯然隻能用于具有親緣關系的程序間進行通信)。fd
-
:表示偏移量,一般設為0,表示從檔案頭開始映射。offset
傳回值:
函數的傳回值為最後檔案映射到程序空間的位址,程序可直接操作起始位址為該值的有效位址。
三、應用示例
mmap_w.c
/* process_mmap_w.c*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#define MAPLEN 0x1000 //十進制4096
//用于程序間通信,一般設定為結構體,用來傳輸資料
struct STU {
int id;
char name[20];
char sex;
};
//自定義的出錯的處理函數
void sys_err(char *str, int exitno) {
perror(str);
exit(exitno);
}
//從終端傳入檔案名
int main(int argc, char *argv[]) {
struct STU *mm;
int fd, i = 0;
// 沒有從終端傳入檔案名産生錯誤
if (argc < 2) {
printf("./a.out filename\n");
exit(1);
}
//根據傳入的 argv[1]檔案名打開相應的臨時檔案
fd = open(argv[1], O_RDWR | O_CREAT, 0777);
//磁盤檔案大小不為零
if (fd < 0)
sys_err("open", 1);
//在檔案MAPLEN位置寫入資料,進而擴從fd檔案大小為MAPLEN
if (lseek(fd, MAPLEN-1, SEEK_SET) < 0)
sys_err("lseek", 3);
if (write(fd, "\0", 1) < 0)
sys_err("write", 4);
//共享記憶體映射
//參數1 :null:由作業系統找記憶體的空位
//參數2:MAPLEN記憶體長度
//參數3:port頁面屬性 讀寫
//參數4: MAP_SHARED 記憶體更改 檔案也更改
//參數5:fd 你要映射的磁盤檔案
//參數6:0 偏移量從 0 開始
mm = mmap(NULL, MAPLEN, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
//映射發生錯誤
if (mm == MAP_FAILED)
sys_err("mmap", 2);
//關閉檔案描述符
close(fd);
while (1) {
//往記憶體中寫入資料
mm->id = i;
sprintf(mm->name, "zhang-%d", i);
if (i % 2 == 0)
mm->sex = 'm';
else
mm->sex = 'w';
i++;
sleep(1);
}
//解除映射關系
munmap(mm, MAPLEN);
return 0;
}
mmap_r.c
/* process_mmap_r.c*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#define MAPLEN 0x1000
struct STU {
int id;
char name[20];
char sex;
};
void sys_err(char *str, int exitno) {
perror(str);
exit(exitno);
}
int main(int argc, char *argv[]) {
struct STU *mm;
int fd, i = 0;
if (argc < 2) {
printf("./a.out filename\n");
exit(1);
}
fd = open(argv[1], O_RDWR);
if (fd < 0)
sys_err("open", 1);
mm = mmap(NULL, MAPLEN, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (mm == MAP_FAILED)
sys_err("mmap", 2);
close(fd);
//釋放我們建立的本地檔案(映射的檔案設定為臨時檔案)
unlink(argv[1]);
while (1) {
printf("%d\n", mm->id);
printf("%s\n", mm->name);
printf("%c\n", mm->sex);
sleep(1);
}
munmap(mm, MAPLEN);
return 0;
}
運作結果:
程序1:寫
程序2:讀
參考來源:
https://blog.csdn.net/windgs_yf/article/details/81146887