一.概述 1.共用記憶體允許多個進程共用物理記憶體的同一塊記憶體區。2.與管道和消息隊列不同,共用記憶體在用戶記憶體空間,不需要內核介入。降低了內核和用戶緩衝區的數據複製開銷。所以這種IPC速度比較快。3.多個進程共用記憶體時需要其他同步機制來控制臨界區,如上一篇...
一.概述
1.共用記憶體允許多個進程共用物理記憶體的同一塊記憶體區。
2.與管道和消息隊列不同,共用記憶體在用戶記憶體空間,不需要內核介入。降低了內核和用戶緩衝區的數據複製開銷。所以這種IPC速度比較快。
3.多個進程共用記憶體時需要其他同步機制來控制臨界區,如上一篇的信號量
二.函數介面
1.創建或打開共用記憶體
1 #include <sys/shm.h> 2 3 int shmget(key_t key, size_t size, int shmflg);
key和shmflg同消息隊列和信號量一樣,這裡不再敘述。
size:需要分配記憶體的大小
2.使用共用記憶體
1 #include <sys/shm.h> 2 3 void *shmat(int shmid, const void *shmaddr, int shmflg);
shmid:shmget()返回的值
shmaddr:把剛剛創建的記憶體指向該指針。如果是NULL,內核會自動選擇。
shmflg:如果shmaddr不為NULL,shmflg控制shmaddr如果指向記憶體。如記憶體只讀,計算記憶體地址倍數等,可以查看man手冊。
3.分離共用記憶體
1 #include <sys/shm.h> 2 3 4 int shmdt(const void *shmaddr);
shmaddr是該進程指向共用記憶體的指針。把該共用記憶體從該進程分離,即該共用記憶體和該進程沒有聯繫了。分離後,共存記憶體依然存在。
4.控制共用記憶體
1 #include <sys/shm.h> 2 3 int shmctl(int shmid, int cmd, struct shmid_ds *buf);
cmd和消息隊列一樣,IPC_RMID是刪除共用記憶體。
三.簡單例子
我們寫2個小程式,第一個創建和拷貝數據到共用記憶體,第二個讀取共用記憶體數據並刪除共用記憶體。
1.創建和拷貝
1 /** 2 * @file shm1.c 3 */ 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <sys/shm.h> 9 10 #define SHARE_MEM_BUF_SIZE 1024 11 12 void err_exit(const char *err_msg) 13 { 14 printf("error:%s\n", err_msg); 15 exit(1); 16 } 17 18 int main(void) 19 { 20 int shm_id; 21 void *share_mem; 22 char *text = "123456"; 23 24 shm_id = shmget(IPC_PRIVATE, SHARE_MEM_BUF_SIZE, 0666 | IPC_CREAT); 25 if (shm_id == -1) 26 err_exit("shmget()"); 27 28 printf("shm_id:%d\n", shm_id); 29 30 /* 把創建的共用記憶體指向該程式的一個指針 */ 31 share_mem = shmat(shm_id, NULL, 0); 32 if (share_mem == (void *)-1) 33 err_exit("shmat()"); 34 35 /* 拷貝數據到共用記憶體 */ 36 memcpy((char *)share_mem, text, strlen(text)); 37 38 /* 分離共用記憶體 */ 39 if (shmdt(share_mem) == -1) 40 err_exit("shmdt()"); 41 42 return 0; 43 }
2.讀取並刪除
1 /** 2 * @file shm2.c 3 */ 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <sys/shm.h> 9 10 #define SHARE_MEM_BUF_SIZE 1024 11 12 void err_exit(const char *err_msg) 13 { 14 printf("error:%s\n", err_msg); 15 exit(1); 16 } 17 18 int main(int argc, const char *argv[]) 19 { 20 if (argc < 2) 21 { 22 printf("usage:%s shm_id\n", argv[0]); 23 exit(1); 24 } 25 26 void *share_mem; 27 int shm_id = atoi(argv[1]); 28 29 /* 把創建的共用記憶體指向該程式的一個指針 */ 30 share_mem = shmat(shm_id, NULL, 0); 31 if (share_mem == (void *)-1) 32 err_exit("shmat()"); 33 34 /* 讀取數據 */ 35 printf("read data:%s\n", (char *)share_mem); 36 37 /* 分離共用記憶體 */ 38 if (shmdt(share_mem) == -1) 39 err_exit("shmdt()"); 40 41 /* 刪除共用記憶體 */ 42 if (shmctl(shm_id, IPC_RMID, 0) == -1) 43 err_exit("shmctl()"); 44 45 return 0; 46 }
四.實驗
1.shm1.c用IPC_PRIVATE方式讓內核自動創建一個key,並分配1024位元組記憶體。第36行把"123456"拷貝到共用記憶體。
2.shm2.c從命令行來指定要使用的共用記憶體,第35行讀取數據,第42行刪除數據。
3.運行shm1後,可以得到共用記憶體的shmid,可以用ipcs -m | grep 'xxx'查看:
可以看到我們分配的1024位元組記憶體。
4.運行shm2接收shmid=50954258的數據並刪除共用記憶體,再用ipcs -m | grep 'xxx'查看:
可以看到讀取了"123456"數據,用ipcs查看時,已被刪除。