兩個不一樣進程A、B共享內存的意思是,同一塊物理內存被映射到進程A、B各自的進程地址空間,進程A能夠即時看到進程B對共享內存中數據的更新,反之,進程B也能夠即時看到進程A對共享內存中數據的更新。c++
共享內存是存在於內核級別的一種資源shell
在系統內核爲一個進程分配內存地址時,經過分頁機制可讓一個進程的物理地址不連續,同時也可讓一段內存同時分配給不一樣的進程。共享內存機制就是經過該原理來實現的,共享內存機制只是提供數據的傳送,如何控制服務器端和客戶端的讀和寫操做互斥,這就須要一些其餘的輔助工具,例如信號量的概念。數組
共享內存能夠說是Linux下最快速、最有效的進程間通訊方式服務器
- 由於進程能夠直接讀寫內存,而不須要任何數據的拷貝
- 管道和消息隊列等通訊方式,須要在內核和用戶空間進行四次的數據拷貝,而共享內存則只拷貝兩次數據:一次從輸入文件到共享內存區,另外一次從共享內存區到輸出文件
- 進程之間在共享內存時,並不老是讀寫少許數據後就解除映射,有新的通訊時,再從新創建共享內存區域。而是保持共享區域,直到通訊完畢爲止,這樣,數據內容一直保存在共享內存中,並無寫回文件。共享內存中的內容每每是在解除映射時才寫回文件的
用於Linux進程通訊共享內存。共享內存函數由shmget、shmat、shmdt、shmctl四個函數組成。ide
shmat函數原型函數
shmat(把共享內存區對象映射到調用進程的地址空間)工具
所需頭文件命令行
#include <sys/types.h> #include <sys/shm.h>
函數說明線程
鏈接共享內存標識符爲shmid的共享內存,鏈接成功後把共享內存區對象映射到調用進程的地址空間,隨後可像本地空間同樣訪問
函數原型code
void *shmat(int shmid, const void *shmaddr, int shmflg)
函數傳入值
shmid 共享內存標識符 shmaddr 指定共享內存出如今進程內存地址的什麼位置,直接指定爲NULL讓內核本身決定一個合適的地址位置 shmflg SHM_RDONLY:爲只讀模式,其餘爲讀寫模式
函數返回值
成功:附加好的共享內存地址 出錯:-1,錯誤緣由存於errno中
shmget()
建立或打開共享內存的函數
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key,int size,int flag);
返回值:成功返回共享內存ID,出錯返回-1
key:建立或打開的共享內存的鍵值
size:共享內存區域大小,只在建立一個新的共享內存時生效
flag:調用函數的操做類型,也可用於設置共享內存的訪問權限,二者經過邏輯或表示
shmdt函數原型
shmdt(斷開共享內存鏈接)
所需頭文件
#include <sys/types.h> #include <sys/shm.h>
函數說明
與shmat函數相反,是用來斷開與共享內存附加點的地址,禁止本進程訪問此片共享內存
函數原型
int shmdt(const void *shmaddr)
函數傳入值
shmaddr:鏈接的共享內存的起始地址
函數返回值
成功:0 出錯:-1,錯誤緣由存於error中
程序中在調用shmget函數時指定key參數值爲IPC_PRIVATE,這個參數的意義是建立一個新的共享內存區,當建立成功後使用shell命令ipcs來顯示目前系統下共享內存的狀態。命令參數-m爲只顯示共享內存的狀態。
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdlib.h> #include <stdio.h> #define BUFSZ 4096 int main(void) { int shm_id;/*共享內存標識符*/ shm_id = shmget(IPC_PRIVATE,BUFSZ,0666); /*建立共享內存*/ if(shm_id < 0) { printf("shmget failed!\n"); exit(1);/*shmget出錯退出*/ } printf("create a shared memory segment successfully:%d\n",shm_id); system("ipcs -m");/*調用ipcs命令查看IPC*/ exit(0); } 運行結果: hyx@hyx-virtual-machine:~/test$ ./create_shm create a shared memory segment successfully:2949133 ------------ 共享內存段 -------------- 鍵 shmid 擁有者 權限 字節 鏈接數 狀態 0x00000000 65536 hyx 600 524288 2 目標 0x00000000 1114113 hyx 600 524288 2 目標 0x00000000 196610 hyx 600 524288 2 目標 0x00000000 393219 hyx 600 524288 2 目標 0x00000000 950276 hyx 600 524288 2 目標 0x00000000 589829 hyx 600 524288 2 目標 0x00000000 622598 hyx 600 16777216 2 0x00000000 655367 hyx 600 16777216 2 目標 0x00000000 753672 hyx 600 524288 2 目標 0x00000000 819209 hyx 600 2097152 2 目標 0x00000000 1146890 hyx 600 1048576 2 目標 0x00000000 1245195 hyx 600 524288 2 目標 0x00000000 1933324 hyx 600 67108864 2 目標 0x00000000 2949133 hyx 666 4096 0
執行ipcs,打印共享內存,信號量和消息隊列的信息:
hyx@hyx-virtual-machine:~/test$ ipcs ------------ 共享內存段 -------------- 鍵 shmid 擁有者 權限 字節 鏈接數 狀態 0x00000000 65536 hyx 600 524288 2 目標 0x00000000 1114113 hyx 600 524288 2 目標 0x00000000 196610 hyx 600 524288 2 目標 0x00000000 393219 hyx 600 524288 2 目標 0x00000000 950276 hyx 600 524288 2 目標 0x00000000 589829 hyx 600 524288 2 目標 0x00000000 622598 hyx 600 16777216 2 0x00000000 655367 hyx 600 16777216 2 目標 0x00000000 753672 hyx 600 524288 2 目標 0x00000000 819209 hyx 600 2097152 2 目標 0x00000000 1146890 hyx 600 1048576 2 目標 0x00000000 1245195 hyx 600 524288 2 目標 0x00000000 1933324 hyx 600 67108864 2 目標 0x00000000 2949133 hyx 666 4096 0 --------- 信號量數組 ----------- 鍵 semid 擁有者 權限 nsems --------- 消息隊列 ----------- 鍵 msqid 擁有者 權限 已用字節數 消息
執行ipcs -m,只打印共享內存段信息:
hyx@hyx-virtual-machine:~/test$ ipcs -m ------------ 共享內存段 -------------- 鍵 shmid 擁有者 權限 字節 鏈接數 狀態 0x00000000 65536 hyx 600 524288 2 目標 0x00000000 1114113 hyx 600 524288 2 目標 0x00000000 196610 hyx 600 524288 2 目標 0x00000000 393219 hyx 600 524288 2 目標 0x00000000 950276 hyx 600 524288 2 目標 0x00000000 589829 hyx 600 524288 2 目標 0x00000000 622598 hyx 600 16777216 2 0x00000000 655367 hyx 600 16777216 2 目標 0x00000000 753672 hyx 600 524288 2 目標 0x00000000 819209 hyx 600 2097152 2 目標 0x00000000 1146890 hyx 600 1048576 2 目標 0x00000000 1245195 hyx 600 524288 2 目標 0x00000000 1933324 hyx 600 67108864 2 目標 0x00000000 2949133 hyx 666 4096 0 hyx@hyx-virtual-machine:~/test$
共享內存ID以命令行參數的形式傳遞給進程。
write_shm.c是寫共享內存,即分10次向共享內存中寫入people結構體的成員數據,(姓名和年齡)數據的值由for循環自動生成。程序的最後使用shmdt將共享內存段從當前的進程空間中脫離掉。
#include <stdio.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <unistd.h> typedef struct { char name[4]; int age; }people; int main(int argc,char** argv) { int shm_id,i; char temp; people *p_map; if(argc != 2)/*命令行參數錯誤*/ { printf("USAGE:atshm < d=identifier>");/*打印幫助消息*/ exit(1); } shm_id = atoi(argv[1]);/*獲得要引入的共享內存段,atoi將字符轉換成整型*/ p_map = (people *)shmat(shm_id,NULL,0);/*shmat:把共享內存區對象映射到調用進程的地址空間*/ temp = 'a'; for(i = 0;i < 10;i++) { temp+=1; memcpy((*(p_map+i)).name,&temp,1); (*(p_map+i)).age = 20+i; /*memcpy:c和c++使用的內存拷貝函數,memcpy函數的功能是從源src所指的內存地址的起始位置開始拷貝n個字節到目標des所指的內存地址的起始位置中,void *memcpy(void *dest, const void *src, size_t n);*/ } if(shmdt(p_map)==-1) { perror("detach error!\n"); } return 0; }
read_shm.c是讀共享內存,即分10次從共享內存中讀出people結構體的成員數據。程序的最後一樣使用shmdt將共享內存段從當前的進程空間中脫離掉。
#include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <unistd.h> typedef struct { char name[4]; int age; }people; int main(int argc,char** argv) { int shm_id,i; people *p_map; if(argc != 2) { printf("USAGE:atshm <idenfifier>"); exit(1); } shm_id = atoi(argv[1]);/*獲得要引入的共享內存段,atoi將字符轉換成整型*/ p_map = (people*)shmat(shm_id,NULL,0);/*shmat:把共享內存區對象映射到調用進程的地址空間*/ for(i=0;i<10;i++) { printf("name:%s ",(*(p_map+i)).name); printf("age %d\n",(*(p_map+i)).age); } if(shmdt(p_map)==-1) { perror("detach error!\n"); } return 0; }
運行結果:
hyx@hyx-virtual-machine:~/test$ ./write_shm 2949133 hyx@hyx-virtual-machine:~/test$ ./read_shm 2949133 name:b age 20 name:c age 21 name:d age 22 name:e age 23 name:f age 24 name:g age 25 name:h age 26 name:i age 27 name:j age 28 name:k age 29 hyx@hyx-virtual-machine:~/test$
信號量的原理是一種數據操做鎖的概念,它自己不具有數據交換的功能,而是經過控制其餘的通訊資源(如文件、外部設備等)來實現進程間通訊。信號量自己不具有數據傳輸的功能,其只是一種外部資源的標識。
信號量,有時也被稱爲信號燈,是在多進程環境下使用的一種設施,它負責協調各個進程,以保證它們可以正確、合理的使用公共資源。信號量分爲單值和多值兩種,前者只能被一個進程得到,後者能夠被若干個進程得到。
以停車場爲例:假設停車場只有三個車位,一開始三個車位都爲空。這時若是同時來了第五輛車,看門人容許其中三輛直接進入,而後放下車欄,剩下的車則必須在入口等待,在此後來的車也都不得不在入口處等待。這時,有一輛車離開停車場,看門人得知後,打開車欄,放入外面的一輛進去,若是又離開兩輛,則又能夠放入兩輛,如此往復。
- 車位:公共資源
- 每輛車:一個進程
- 看門人:信號量的做用