以下内容为本人的学习笔记,如需要转载,请声明原文链接 微信公众号「ENG八戒」https://mp.weixin.qq.com/s/IvPHnEsC6ZdIHaFL8Deazg
共享内存
我们在进程间传输比较大的数据块时,通常选用共享内存的方式。共享内存大小也是有限制的,系统范围内能申请到的最大共享内存数量是 4096 个,每个最大空间为 18014398509465599 kbytes,所有共享内存最多占用空间为 18014398509481980 kbytes,当然每个共享内存最小限制为 1 字节。
如果需要查看修改限制值,可以按顺序分别参考下面的几个内核文件:
/proc/sys/kernel/shmmni
/proc/sys/kernel/shmmax
/proc/sys/kernel/shmall
通过 shmget() 申请共享内存资源,参数 key 指定 IPC key,size 是分配的共享内存大小(创建时有效,必须为 PAGE_SIZE 的倍数大小),参数 shmflg 指定标志类似消息队列和信号量。
int shmid = shmget(key, PAGE_SIZE, IPC_CREAT | 0666);
if (shmid == -1) {
printf("shmget %s", strerror(errno));
}
一般 PAGE_SIZE 默认 4096,如果你需要查看当前系统下的配置值,可以:
$ pagesize
通过共享内存传输数据,其实就是在进程同步的情况下读写指定的内存空间,一般的进程同步采用信号量。读写前,被指定的进程内存空间必须先和共享内存绑定,绑定通过函数 shmat(),解绑通过函数 shmdt()。
#include <sys/shm.h>
void *shmat(int shmid, const void *_Nullable shmaddr, int shmflg);
int shmdt(const void *shmaddr);
绑定和解绑无须在每次发送接收共享内存的数据时都执行,如果是用户自己分配内存空间再绑定会增加内存泄漏的安全风险。
所以最佳实践是,在发送最开始时向系统申请自动绑定并返回被绑定的进程内部地址空间即可,接收同理,但是接收端在进程退出前应该负责解绑操作。
如何向系统申请自动绑定?在调用 shmat() 时,参数 shmaddr 用于指定被绑定的进程内部地址空间的地址,设为 NULL 即可。
发送数据
static char *pshm = NULL;
if (!pshm) {
...
// 向系统申请自动绑定进程内部地址空间
// 并保存返回的地址
pshm = (char*)shmat(shmid, 0, 0);
if ((char*)-1 == pshm) {
printf("shmat %s", strerror(errno));
return; // 退出
}
}
... // 请求信号量
// 将长度为 len 的数据 data 写入被绑定的进程内部地址空间
memcpy(pshm, data, len);
... // 释放信号量
上面这段代码通常会封装成一个发送函数,pshm 被声明为 static 的变量就为了不用每次进入函数都重新绑定进程内部地址空间。实际写入数据时,需要利用信号量同步。
接收数据
接收数据不需要手动调用接收函数,一般通过创建子线程,在子线程内部循环地读取被绑定的进程内部地址空间的数据即可,当然,读取同样需要利用信号量同步。
char *data = NULL;
...
// 向系统申请自动绑定进程内部地址空间
// 并保存返回的地址
data = (uint8_t*)shmat(shmid, 0, 0);
if ((uint8_t*)-1 == data) {
printf("shmat %s", strerror(errno));
return; // 退出
}
while (1) {
... // 请求信号量
// 将被绑定的进程内部地址空间 data 的数据
// 另存到大小为 size 的缓冲区 buf
memcpy(buf, data, size);
... // 释放信号量
}
// 退出前解绑
int ret = shmdt(data);
if (-1 == ret) {
printf("shmdt %s", strerror(errno));
}
查看当前 IPC 状态
Linux 系统提供了 ipcs 指令用于查看 IPC 资源的状态信息
$ ipcs -a
------ Message Queues --------
key msqid owner perms used-bytes messages
0x0f050002 0 user 666 0 0
0x0e050002 1 user 666 0 0
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 131072 user 600 40960 2 dest
0x00000000 131074 user 600 40960 2 dest
0x00000000 131075 user 600 16384 2 dest
...
------ Semaphore Arrays --------
key semid owner perms nsems
0x09050002 0 user 666 2
0x0c050002 1 user 666 2