前言:天下武功為快不破!在信息爆炸、快速發展的新時代...,扯遠了...。進程間通信方式有很多,但最快的方式你知道么?由我娓娓道來...
一、共享內存方式
主角閃亮登場了,噔噔瞪...,最快的方式就是共享內存了。實現共享內存的方式主要有兩種:
- 存儲映射I/O mmap函數實現
- shmget函數
感覺學兩個以上相同的知識時,就會學他們的區別,我也會避免不了進入俗套,也要簡單來說它們的區別:
注:此圖引自《unix環境高級編程》
看到圖片中“主要區別”四個大字了么?別告訴我:你近視看不到,打死你個龜孫!開玩笑啦,哈哈哈!只希望在學習知識時,不要感覺太乏味哦。在下文介紹完兩種方式之后,你就會不明白它們的區別了。
二、mmap函數實現共享內存
1、存儲映射I/O
先來畫個見圖來介紹一下實現原理,如下圖: PS:依舊是全博客園最丑圖,不接受反駁!!!
mmap函數主要作用就是將磁盤文件映射到內存中,並返回這段內存的首地址,並可以將這塊內存來當做“數組”來處理。要對這個圖有一個模型(雖然是全博客園最丑圖),對接下來的講解有一定幫助。
2、mmap函數及相關函數
原型:void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
返回:成功:返回創建的映射區首地址;失敗:MAP_FAILED宏,注意錯誤跟普通的不一樣!
參數說明:
addr: 建立映射區的首地址,由Linux內核指定。使用時,直接傳遞NULL
length: 欲創建映射區的大小
prot: 映射區權限PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE
flags: 標志位參數(常用於設定更新物理區域、設置共享、創建匿名映射區)
MAP_SHARED: 會將映射區所做的操作反映到物理設備(磁盤)上。
MAP_PRIVATE: 映射區所做的修改不會反映到物理設備。
fd: 用來建立映射區的文件描述符
offset: 映射文件的偏移(4k的整數倍)
3、munmap函數
原型:int munmap(void *addr, size_t length); 成功:0; 失敗:-1
功能:同malloc函數申請內存空間類似的,mmap建立的映射區在使用結束后也應調用類似free的函數來釋放。
4、父子進程用mmap示例程序
程序主要用共享內存進行通信,如下:

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/wait.h> int var = 100; int main(void) { int *p; pid_t pid; int fd; fd = open("temp", O_RDWR|O_CREAT|O_TRUNC, 0644); if(fd < 0){ perror("open error"); exit(1); } unlink("temp"); //刪除臨時文件目錄項,使之具備被釋放條件. ftruncate(fd, 4); //p = (int *)mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); p = (int *)mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); if(p == MAP_FAILED){ //注意:不是p == NULL perror("mmap error"); exit(1); } close(fd); //映射區建立完畢,即可關閉文件 pid = fork(); //創建子進程 if(pid == 0){ *p = 2000; var = 1000; printf("child, *p = %d, var = %d\n", *p, var); } else { sleep(1); printf("parent, *p = %d, var = %d\n", *p, var); wait(NULL); int ret = munmap(p, 4); //釋放映射區 if (ret == -1) { perror("munmap error"); exit(1); } } return 0; }
三、匿名映射
1、說明
通過使用我們發現,使用映射區來完成文件讀寫操作十分方便,父子進程間通信也較容易。但缺陷是,每次創建映射區一定要依賴一個文件才能實現。通常為了建立映射區要open一個temp文件,創建好了再unlink、close掉,比較麻煩。 可以直接使用匿名映射來代替。其實Linux系統給我們提供了創建匿名映射區的方法,無需依賴一個文件即可創建映射區。同樣需要借助標志位參數flags來指定。
使用MAP_ANONYMOUS (或MAP_ANON), 如:
int *p = mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
"4"隨意舉例,該位置表大小,可依實際需要填寫。
需注意的是,MAP_ANONYMOUS和MAP_ANON這兩個宏是Linux操作系統特有的宏。在類Unix系統中如無該宏定義,可使用如下兩步來完成匿名映射區的建立。
① fd = open("/dev/zero", O_RDWR);
② p = mmap(NULL, size, PROT_READ|PROT_WRITE, MMAP_SHARED, fd, 0);
2、用"/dev/sero"示例匿名映射
程序如下:

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> int main(void) { int *p; pid_t pid; int fd; fd = open("/dev/zero", O_RDWR); p = mmap(NULL, 400, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); if(p == MAP_FAILED){ //注意:不是p == NULL perror("mmap error"); exit(1); } pid = fork(); //創建子進程 if(pid == 0){ *p = 2000; printf("child, *p = %d\n", *p); } else { sleep(1); printf("parent, *p = %d\n", *p); } munmap(p, 4); //釋放映射區 return 0; }
總結:shmget函數會在另一篇博客介紹,歡迎評論交流