Linux 系统下的进程间通信 IPC 入门 下

以下内容为本人的学习笔记,如需要转载,请声明原文链接 微信公众号「ENG八戒」mp.weixin.qq.com/s/IvPHnEsC6...

共享内存

我们在进程间传输比较大的数据块时,通常选用共享内存的方式。共享内存大小也是有限制的,系统范围内能申请到的最大共享内存数量是 4096 个,每个最大空间为 18014398509465599 kbytes,所有共享内存最多占用空间为 18014398509481980 kbytes,当然每个共享内存最小限制为 1 字节。

如果需要查看修改限制值,可以按顺序分别参考下面的几个内核文件:

bash 复制代码
/proc/sys/kernel/shmmni
/proc/sys/kernel/shmmax
/proc/sys/kernel/shmall

通过 shmget() 申请共享内存资源,参数 key 指定 IPC key,size 是分配的共享内存大小(创建时有效,必须为 PAGE_SIZE 的倍数大小),参数 shmflg 指定标志类似消息队列和信号量。

ini 复制代码
int shmid = shmget(key, PAGE_SIZE, IPC_CREAT | 0666);
if (shmid == -1) {
    printf("shmget %s", strerror(errno));
}

一般 PAGE_SIZE 默认 4096,如果你需要查看当前系统下的配置值,可以:

ruby 复制代码
$ pagesize

通过共享内存传输数据,其实就是在进程同步的情况下读写指定的内存空间,一般的进程同步采用信号量。读写前,被指定的进程内存空间必须先和共享内存绑定,绑定通过函数 shmat(),解绑通过函数 shmdt()。

arduino 复制代码
#include <sys/shm.h>
void *shmat(int shmid, const void *_Nullable shmaddr, int shmflg);
int shmdt(const void *shmaddr);

绑定和解绑无须在每次发送接收共享内存的数据时都执行,如果是用户自己分配内存空间再绑定会增加内存泄漏的安全风险。

所以最佳实践是,在发送最开始时向系统申请自动绑定并返回被绑定的进程内部地址空间即可,接收同理,但是接收端在进程退出前应该负责解绑操作。

如何向系统申请自动绑定?在调用 shmat() 时,参数 shmaddr 用于指定被绑定的进程内部地址空间的地址,设为 NULL 即可。

发送数据

scss 复制代码
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 的变量就为了不用每次进入函数都重新绑定进程内部地址空间。实际写入数据时,需要利用信号量同步。

接收数据

接收数据不需要手动调用接收函数,一般通过创建子线程,在子线程内部循环地读取被绑定的进程内部地址空间的数据即可,当然,读取同样需要利用信号量同步。

scss 复制代码
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 资源的状态信息

sql 复制代码
$ 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

相关推荐
wowocpp1 小时前
查看 linux ubuntu 分区 和 挂载 情况 lsblk
linux·运维·ubuntu
wowocpp1 小时前
查看 磁盘文件系统格式 linux ubuntu blkid ext4
linux·数据库·ubuntu
龙鸣丿2 小时前
Linux基础学习笔记
linux·笔记·学习
耶啵奶膘4 小时前
uniapp-是否删除
linux·前端·uni-app
闲晨4 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
2401_850410835 小时前
文件系统和日志管理
linux·运维·服务器
XMYX-05 小时前
使用 SSH 蜜罐提升安全性和记录攻击活动
linux·ssh
二十雨辰7 小时前
[linux]docker基础
linux·运维·docker
饮浊酒8 小时前
Linux操作系统 ------(3.文本编译器Vim)
linux·vim
lihuhelihu8 小时前
第3章 CentOS系统管理
linux·运维·服务器·计算机网络·ubuntu·centos·云计算