共享內(nèi)存的linux IPC的一個(gè)方式。最簡單的解釋就是同一段物理內(nèi)存被映射到不同進(jìn)程的地址空間。任和一個(gè)被映射的進(jìn)程對該內(nèi)存的寫操作對其他被映射是可見的。
可以在命令查看當(dāng)前系統(tǒng)共享內(nèi)存的信息。
下面我們有4個(gè)文件,分別是公共文件,shm_write(創(chuàng)建共享內(nèi)存) shm_read(讀取共享內(nèi)存內(nèi)容) shm_clean(清除共享內(nèi)存內(nèi)容) common.h一個(gè)公共文件
common.h
1 #ifndef _COMMON_H
2 #define _COMMON_H
3
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <sys/shm.h>
7 #include <stdlib.h>
8
9 #define SHM_KEY 0x00000010
10 #define BUFFSIZE 0x00001000
11
12 #define SHM_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
13
14 struct shm_mm
15 {
16 int num;
17 char buff[BUFFSIZE];
18 };
19
20 #endif
shm_write.c
1 #include "common.h"
2 #include <stdio.h>
3
4 int main()
5 {
6 int shmid;
7 shmid = shmget(SHM_KEY, sizeof(struct shm_mm), IPC_EXCL|IPC_CREAT|SHM_PERMS);
8 if(shmid == -1)
9 {
10 printf("shmget failed\n");
11 exit(1);
12 }
13
14 struct shm_mm *pshm = shmat(shmid, NULL, 0);
15 if(pshm == (void*)-1)
16 {
17 printf("shmat failed\n");
18 exit(2);
19 }
20
21 pshm->num = 100;
22 for(int i = 0; i < 10 && i < BUFFSIZE; i++)
23 {
24 pshm->buff[i] = 'a';
25 }
26
27 }
shm_read.c
1 #include "common.h"
2 #include <stdio.h>
3
4 int main()
5 {
6 int shmid;
7 shmid = shmget(SHM_KEY,0, 0);
8 if(shmid == -1)
9 {
10 printf("shmget failed\n");
11 exit(1);
12 }
13
14 struct shm_mm *pshm = shmat(shmid, NULL, 0);
15 if(pshm == (void*)-1)
16 {
17 printf("shmat failed\n");
18 exit(2);
19 }
20
21 printf("num=%d\n", pshm->num);
22 for(int i = 0; i < 10 && i < BUFFSIZE; i++)
23 {
24 printf("%c\t", pshm->buff[i]);
25 }
26 printf("\n");
27
28 getchar();
29 return 0;
30 }
shm_clean.c
1 #include "common.h"
2 #include <stdio.h>
3
4 int main()
5 {
6 int shmid = shmget(SHM_KEY, 0, 0);
7 if(-1 == shmid)
8 {
9 printf("shmget failed\n");
10 exit(0);
11 }
12 int ret = shmctl(shmid, IPC_RMID, 0);
13 if(-1 == ret)
14 {
15 printf("shmctl failed\n");
16 exit(1);
17 }
18 return 0;
19 }

我們運(yùn)行shm_write進(jìn)程
查看當(dāng)前系統(tǒng)的共享內(nèi)存
我們可以看到最后一行, 第一列的就是我們代碼里面的SHM_KEY 權(quán)限也是我們自己設(shè)定的 SHM_PERMS, 大小是sizeof(shm_mm)。 因?yàn)閟hm_write進(jìn)程以退出,所以現(xiàn)在attach在該內(nèi)存的進(jìn)程數(shù)量為0。
我們啟動(dòng)shm_read
read進(jìn)程讀到了write寫進(jìn)去的數(shù)據(jù).
現(xiàn)在我們可以啟動(dòng)clean進(jìn)程清除剛才創(chuàng)建的貢獻(xiàn)內(nèi)存。也可以用命令 ipcrm -m shmid 清除掉對于的共享內(nèi)存。
通過上述實(shí)現(xiàn),我們看到,當(dāng)進(jìn)程退出后,內(nèi)核自動(dòng)會(huì)把該進(jìn)程和共享內(nèi)存的映射給清掉,就是我們通過ipcs -m 看到的attach的子段。如果我們想在進(jìn)程不退出就把這個(gè)映射這清掉。通過調(diào)用shmdt即可。
和其他共享數(shù)據(jù)一下,當(dāng)多個(gè)進(jìn)程對同一個(gè)共享內(nèi)存進(jìn)行讀寫的時(shí)候,仍然會(huì)有競爭。所以我們需要一些如信號(hào)量,進(jìn)程鎖等高級(jí)的進(jìn)程同步控制原語來進(jìn)行同步操作。
當(dāng)然,共享內(nèi)存還受到一些參數(shù)的影響.
/proc/sys/kernel/shmall:限制系統(tǒng)用在共享內(nèi)存上的內(nèi)存總頁數(shù)。注意是頁數(shù),單位為4k。
/proc/sys/kernel/shmmax:限制一個(gè)共享內(nèi)存段的最大長度,字節(jié)為單位。
/proc/sys/kernel/shmmni:限制整個(gè)系統(tǒng)可創(chuàng)建的最大的共享內(nèi)存段個(gè)數(shù)。