上篇文章:Linux操作系统4-进程间通信3(基于管道的进程池设计)-CSDN博客
本篇Gitee代码:myLerningCode/l24 · 橘子真甜/Linux操作系统与网络编程学习 - 码云 - 开源中国 (gitee.com)
本篇重点:使用共享内存来实现两个进程之间的通信
一. 共享内存的原理
两个进程想要通信,需要让两个进程看到(访问)同一份资源或者空间。管道文件是内存级文件,可以让不同的进程进程访问。
而共享内存的原理是
1 在物理内存中申请一块中间
2 将创建好的内存通过文件页表映射道两个进程的虚拟地址空间中,这样两个进程就能够进行通信(称为进程与共享内存的挂接)
3 不需要通信了,取消共享内存和进程虚拟地址空间的映射关系(去关联)然后师释放共享内存
共享内存是一种通信方式,所有想要通信的进程都可以使用。且OS中一定存在一个或者多个共享内存用于进程的通信。
两个进程通过共享内存进行通信的示意图如下 :
共享内存:让不同的进程可以看到同一块物理内存
二. 共享内存的创建
2.1 系统调用shmget
这个系统调用帮助我们在物理内存中创建一个共享内存。
//所需头文件
#include <sys/ipc.h>
#include <sys/shm.h>
//shmget 用于获取一个共享内存段
int shmget(key_t key, size_t size, int shmflg)
//参数介绍
size: 创建共享内存的大小,单位是字节
shmflg: 标志位,类似与我们的open
IPC_CREAT 如果创建的共享内存不存在,就会创建,若存在就会获取这个共享内存
IPC_EXCL 单独使用无意义
IPC_CREAT | IPC_EXEL 共享内存不存在就会创建,如果存在就会出错返回。一般用于第一次创建共享内存
我们使用的时候一般需要加上 0666用于更改权限
key: 用于保证共享内存的唯一性,不同的key就会创建不同的共享内存
返回值:成功返回标识符,失败返回-1
2.2 ftok获取key值
头文件
#include <sys/types.h>
#include <sys/ipc.h>
//函数原型
key_t ftok(const char* name, int proj_id)
//将一个项目名为name,标识符为proj_id转化为一个 System V 的key
如果两个进程的name和proj_id是一样的,那么它们创建的共享内存就是一样的
成功返回key,失败返回-1
2.3 创建共享内存代码与示例
示例代码如下:
#include <iostream>
#include <cassert>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
// 当前的绝对路径用于获取key
#define PATHNAME "."
#define PROJ_ID 2025221
int main()
{
// 获取一个key
key_t key = ftok(PATHNAME, PROJ_ID);
assert(key != -1);
// 打印key
printf("0x%x\n", key);
//创建共享内存
int sid = shmget(key,1024,IPC_CREAT | IPC_EXCL | 0666);
assert(sid != -1);
return 0;
}
运行结果如下:
可以看到,一个OS中,可能存在非常多的共享内存,为了标识这个共享内存的唯一性,我们需要使用一个key来创建共享内存。
共享内存 = 物理内存 + 共享内存相关属性
key既保证了共享内存的唯一性,两个进程也能通过key值来关联同一个共享内存以便通信
三. 使用命令查看和删除共享内存
3.1 查看命令 ipcs -m
ipcs 这个命令是用于查看System V 的资源的。
如下图:
上图中依次是消息队列,共享内存,信号量
如果只需要查看共享内存只需要使用 ipcs -m 即可。
如下图:
上图就是我们使用test创建的一个共享内存。
为什么我们的进程退出了,共享内存还在呢?
这是因为共享内存是OS进行管理的,生命周期随OS而不随创建它的进程
3.2 删除命令 ipcrm -m
使用 ipcrm -m + 共享内存的shmid 即可删除这个共享内存
如下图:
key可以唯一标识一个共享内存,我们为什么不用key去删除而是用shmid去删除这个共享内存呢?
因为key由OS管理,用户无法操作。