標籤:
System V共用記憶體機制: shmget shmat shmdt shmctl
原理及實現:
system V IPC機制下的共用記憶體本質是一段特殊的記憶體地區,進程間需要共用的資料被放在該共用記憶體地區中,所有需要訪問該共用地區的進程都要把該共用區域對應到本進程的地址空間中去。這樣一個使用共用記憶體的進程可以將資訊寫入該空間,而另一個使用共用記憶體的進程又可以通過簡單的記憶體讀操作擷取剛才寫入的資訊,使得兩個不同進程之間進行了一次資訊交換,從而實現進程間的通訊。
共用記憶體允許一個或多個進程通過同時出現在它們的虛擬位址空間的記憶體進行通訊,而這塊虛擬記憶體的頁面被每個共用進程的頁表條目所引用,同時並不需要在所有進程的虛擬記憶體都有相同的地址。進程對象對於共用記憶體的訪問通過key(鍵)來控制,同時通過key進行存取權限的檢查。
函數定義如下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
key_t ftok(const char *pathname, int proj_id);
函數ftok用於建立一個關鍵字,可以用該關鍵字關聯一個共用記憶體段。
參數pathname為一個全路徑檔案名稱,並且該檔案必須可訪問。
參數proj_id通常傳入一非0字元
通過pathname和proj_id組合可以建立唯一的key
如果調用成功,返回一關鍵字,否則返回-1
int shmget(key_t key, int size, int shmflg);
函數shmget用於建立或開啟一共用記憶體段,該記憶體段由函數的第一個參數唯一建立。函數成功,則返回一個唯一的共用記憶體標識號(相當於進程號,唯一的標識著共用記憶體),失敗返回-1。
參數key是一個與共用記憶體段相關聯關鍵字,如果事先已經存在一個與指定關鍵字關聯的共用記憶體段,則直接返回該記憶體段的標識,表示開啟,如果不存在,則建立一個新的共用記憶體段。key的值既可以用ftok函數產生,也可以是IPC_RPIVATE(用於建立一個只屬於建立進程的共用記憶體,主要用於父子通訊),表示總是建立新的共用記憶體段;
參數size指定共用記憶體段的大小,以位元組為單位;
參數shmflg是一掩碼合成值,可以是存取權限值與(IPC_CREAT或IPC_EXCL)的合成。IPC_CREAT表示如果不存在該記憶體段,則建立它。IPC_EXCL表示如果該記憶體段存在,則函數返回失敗結果(-1)。如果調用成功,返回記憶體段標識,否則返回-1
void *shmat(int shmid, const void *shmaddr, int shmflg);
函數shmat將共用記憶體段映射到進程空間的某一地址。
參數shmid是共用記憶體段的標識 通常應該是shmget的成功傳回值
參數shmaddr指定的是共用記憶體串連到當前進程中的地址位置。通常是NULL,表示讓系統來選擇共用記憶體出現的地址。
參數shmflg是一組位標識,通常為0即可。
如果調用成功,返回映射後的進程空間的首地址,否則返回(char *)-1。
int shmdt(const void *shmaddr);
函數shmdt用於將共用記憶體段與進程空間分離。
參數shmaddr通常為shmat的成功傳回值。
函數成功返回0,失敗時返回-1.注意,將共用記憶體分離並沒刪除它,只是使得該共用記憶體對當前進程不在可用。
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
函數shmctl是共用記憶體的控制函數,可以用來刪除共用記憶體段。
參數shmid是共用記憶體段標識 通常應該是shmget的成功傳回值
參數cmd是對共用記憶體段的操作方式,可選為IPC_STAT,IPC_SET,IPC_RMID。通常為IPC_RMID,表示刪除共用記憶體段。
參數buf是表示共用記憶體段的資訊結構體資料,通常為NULL。
例如shmctl(kshareMem,IPC_RMID,NULL)表示刪除調共用記憶體段kHareMem
樣本:
shm1.c
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<unistd.h> 5 #include<sys/types.h> 6 #include<sys/ipc.h> 7 #include<sys/shm.h> 8 9 int main(int *argc, char *argv[])10 {11 key_t my_key;12 int my_shm;13 char *pstr;14 15 //1,建立一個關鍵字,使其關聯一個共用記憶體段,返回關鍵字16 my_key = ftok("./temp.c",123);17 18 //2,建立或開啟一個共用記憶體段,返回共用記憶體段標誌號19 my_shm = shmget(my_key,1024,0666 | IPC_CREAT);20 if(my_shm == -1)21 {22 printf("shmget error!\n");23 exit(1);24 }25 26 //3,將共用記憶體段映射到進程空間的某一地址,返回映進程射空間的首地址27 pstr = (char*)shmat(my_shm,NULL,0);28 29 strcpy(pstr,"Hello world!\n");30 sleep(5);31 printf("recv from 2:%s\n",pstr);32 33 //4,將共用記憶體段與進程空間分離34 shmdt(pstr);35 36 //5,刪除共用記憶體段37 shmctl(my_shm,IPC_RMID,NULL); 38 39 return 0;40 }
shm2.c
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<unistd.h> 5 #include<sys/types.h> 6 #include<sys/ipc.h> 7 #include<sys/shm.h> 8 9 int main(int *argc, char *argv[])10 {11 key_t my_key;12 int my_shm;13 char *pstr;14 15 //1,建立關鍵字16 my_key = ftok("./temp.c",123);17 18 //2,建立或開啟共用記憶體段19 my_shm = shmget(my_key,1024,0666);20 if(my_shm == -1)21 {22 printf("Shmget error!\n");23 exit(1);24 }25 26 //3,將共用記憶體段映射到某一進程空間27 pstr = (char*)shmat(my_shm,NULL,0);28 printf("recv from 1:%s\n",pstr);29 strcpy(pstr,"How are you!\n");30 31 //4將共用記憶體段與進程空間分離32 shmdt(pstr);33 34 return 0;35 }
Linux IPC之共用記憶體