1.特色:
1)共享內存是一種最爲高效的進程間通訊方式,進程能夠直接讀寫內存,而不須要任何數據的拷貝。如管道當在內核空間建立之後,用戶空間須要內存 拷貝,須要拷貝數據,因此效率低。
2)爲了在多個進程間交換信息,內核專門留出了一塊內存區,能夠由須要訪問的進程將其映射到本身的私有地址空間app
3)進程就能夠直接讀寫這一內存區而不須要進行數據的拷貝,從而大大提升的效率。函數
4)因爲多個進程共享一段內存,所以也須要依靠某種同步機制,如互斥鎖和信號量等測試
2.共享內存的使用步驟:spa
1)建立/打開共享內存code
2)映射共享內存。即把指定的共享內存映射到進程的地址空間用於訪問對象
3)撤銷共享內存映射blog
4)刪除共享內存對象進程
3.相關函數:ip
1)key_t ftok(const char *pathname, int proj_id);內存
功能:產生一個獨一無二的key值
參數:Pathname:已經存在的且可訪問文件的名字
Proj_id:一個字符(由於只用低8位),生成key的數字,不能爲0
返回值:成功:key值;失敗:-1
2)int shmget(key_t key, size_t size, int shmflg);
功能:建立或打開共享內存對象
參數:key 鍵值 ; size 共享內存的大小 ; shmflg IPC_CREAT|IPC_EXCL|0777(標誌位,是否新建,和權限)
返回值:成功 shmid(共享內存ID) ; 出錯 -1
3)void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:映射共享內存,即把指定的共享內存映射到進程的地址空間用於訪問
參數:shmid 共享內存的id號 ; shmaddr 通常爲NULL,表示由系統自動完成映射,若是不爲NULL,那麼有用戶指定
shmflg:SHM_RDONLY就是當前進程對該共享內存只能進行讀操做 0 可讀可寫
返回值:成功:完成映射後的地址,出錯:-1的地址
用法:(p = (char *)shmat(shmid,NULL,0)) == (char *)-1 (對-1強轉成字符型地址)
4)int shmdt(const void *shmaddr);
功能:取消映射
參數:要取消的地址
返回值:成功0 ;失敗的-1
5)int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:(刪除共享內存),對共享內存進行各類操做
參數:shmid 共享內存的id號 ; cmd IPC_STAT 得到shmid屬性信息,存放在第三參數
IPC_SET 設置shmid屬性信息,要設置的屬性放在第三參數
IPC_RMID:刪除共享內存,此時第三個參數爲NULL便可
返回: 成功0 ; 失敗-1
用法:shmctl(shmid,IPC_RMID,NULL);
補充:
一、IPC對象建立後一直存在,直到被顯示的刪除,及最後一個進程要刪除IPC對象
二、每一個IPC對象除了有ID以外還有相關聯的key值(IPC對象的屬性),key值做用,經過key值,不一樣的進程可以找到打開同一個IPC對象,由於IPC對象建立好之後,他的ID是隨機分配的,只有建立IPC對象的進程才能直接得到這個ID,其餘進程是不知道這個ID的,其餘進程就經過key去得到這個ID,經過key打開同一個IPC對象。key值爲0表示私有的。不一樣的進程用ftok函數,生成的key值要同樣,及ftok函數的參數就要保持一致。
例子:
經過終端輸入信息,寫入到共享內存中,而後打印共享內存中的數據
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <errno.h> int main(int argc, const char *argv[]) { key_t key; //共享內存的惟一標識 key 值 int shmid; // char *p = NULL; // 函數原型 key_t ftok(const char *pathname, int proj_id);; key = ftok("./app",'a'); //建立key值 if(key < 0) { perror("fail ftok "); exit(1); }//共享內存 不存在,建立 shmid = shmget(key,128,IPC_CREAT|IPC_EXCL|0777);// 建立/打開共享內存,返回id根據id映射 if(shmid < 0) { if(errno == EEXIST)//文件存在時,直接打開文件獲取shmid { printf("file eexist"); shmid = shmget(key,128,0777); //若是建立了,直接打開 } else { perror("shmget fail "); exit(1); } } p = (char *)shmat(shmid,NULL,0);//映射,返回地址,根據地址操做,錯誤 返回 -1 的地址 if( p == (char *)(-1) ) //錯誤形式判斷 { perror("shmat fail "); exit(1); } read(0,p,10);//從終端讀數據,寫入p指向的空間 printf("%s\n",p); //打印p指向空間的內容 shmdt(p);//解除映射 //int shmctl(int shmid, int cmd, struct shmid_ds *buf); shmctl(shmid,IPC_RMID,NULL); //刪除 return 0; }
測試:終端輸入123 寫入共享內存中,而後經過共享內存打印出來
共享內存總結;
(1)key 值得獲取,根據不一樣的key值得到這塊共享內存惟一的id 根據這個惟一的 id 不一樣進程實現共同訪問這塊共享內存(進程間想訪問同一塊共享內存,就要獲得這個共享內存惟一的id)
(2) key值經過函數 ftok 函數獲取,函數的功能是根據不一樣的文件名,不一樣的字符獲得這個不一樣的 key 值
(3) 固然這個key值其實就是一個整數,也能夠經過給定肯定的數建立 / 打開一塊共享內存,使用 ftok 的目的是防止本身亂填數字,形成不一樣進程間訪問衝突