初窥linux共享内存
共享内存的linux IPC的一个方式。最简单的解释就是同一段物理内存被映射到不同进程的地址空间。任和一个被映射的进程对该内存的写操作对其他被映射是可见的。
可以在命令查看当前系统共享内存的信息。
下面我们有4个文件,分别是公共文件,shm_write(创建共享内存) shm_read(读取共享内存内容) shm_clean(清除共享内存内容) common.h一个公共文件
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 }
![read_out.png](https://img.haomeiwen.com/i541012/8ff9b7b6ec4b5676.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
我们运行shm_write进程
查看当前系统的共享内存
我们可以看到最后一行, 第一列的就是我们代码里面的SHM_KEY 权限也是我们自己设定的 SHM_PERMS, 大小是sizeof(shm_mm)。 因为shm_write进程以退出,所以现在attach在该内存的进程数量为0。
我们启动shm_read
read进程读到了write写进去的数据.
现在我们可以启动clean进程清除刚才创建的贡献内存。也可以用命令 ipcrm -m shmid 清除掉对于的共享内存。
通过上述实现,我们看到,当进程退出后,内核自动会把该进程和共享内存的映射给清掉,就是我们通过ipcs -m 看到的attach的子段。如果我们想在进程不退出就把这个映射这清掉。通过调用shmdt即可。
和其他共享数据一下,当多个进程对同一个共享内存进行读写的时候,仍然会有竞争。所以我们需要一些如信号量,进程锁等高级的进程同步控制原语来进行同步操作。
当然,共享内存还受到一些参数的影响.
/proc/sys/kernel/shmall:限制系统用在共享内存上的内存总页数。注意是页数,单位为4k。
/proc/sys/kernel/shmmax:限制一个共享内存段的最大长度,字节为单位。
/proc/sys/kernel/shmmni:限制整个系统可创建的最大的共享内存段个数。