System V 共享内存
当需要有进程间通信的需求时,程序员为了复用之前的代码创建了管道,而管道的原理是基于文件的。随着时代的发展,程序员逐渐发现有一些是管道不能解决的问题,因此不得不真正创建了一个可以进行通信的资源。此时,在上层就有公司定制了一套 System V 标准,由其他公司按照这个标准进行不同的实现。
共享内存区是最快的 IPC 形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来回传递彼此的数据。
共享内存原理
- 共享内存是实实在在地在物理内存中开辟内存块;
- 有了物理地址,那么就需要与虚拟地址建立映射关系;
- 如果要释放共享内存时,就需要删除映射关系。
而这些操作只有操作系统能做到,而操作系统又对上提供了一套系统调用,则用户就可以通过系统调用完成。
既然能开辟内存空间,那么如果有多个进程开辟多个内存空间,OS 要知道哪些内存空间是由谁开辟的,这块内存空间是刚建立的还是正在销毁的 --> 这决定了 OS 要管理内存空间 --> 如何管理呢?
先描述!在组织!
创建共享内存 - 研究特性
shmget
IPC_CREAT 单独:如果创建的共享内存不存在,就创建;如果存在,就获取 IPC_EXCL:不能单独使用,没有意义 IPC_CREAT | IPC_EXCL:如果共享内存不存在,就创建,返回的就是全新的 shm;如果已经存在,出错返回!
返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回 -1
key 是由用户进行传入,那为什么要这样做呢?为什么需要配合 ftok 函数进行使用呢?
- 公共标识符:进程 A 使用这个 key(比如 1234)创建了一块共享内存。之后,进程 B 也拿着同样的 key(1234)向操作系统申请,操作系统一看 key 已经存在,就会把已经创建好的那块共享内存的访问权限也赋给进程 B。这样,两个进程就指向了同一块物理内存,可以进行通信了。如果 key 是由内核随机生成并只返回给创建者,那其他进程就无从知晓了。
- 正如你的图中所展示的,直接在代码里写一个固定的数字(key_t key = 1234;)作为键值有风险,因为你无法保证这个数字在整个操作系统里是唯一的,万一和其他程序冲突了就会出问题。为了解决这个问题,ftok() 函数提供了一种更可靠的方式来生成这个 key。只要所有进程都使用相同的路径和 ID,ftok() 就能保证为它们生成完全相同的 key。
那么 key 是保存在哪的呢?ipc_perm 的结构体里:
struct ipc_perm {
key_t key;
__compat_uid_t uid;
__compat_gid_t gid;
__compat_uid_t cuid;
__compat_gid_t cgid;
compat_mode_t mode;
unsigned short seq;
};
创建共享内存
进程退出的时候,曾经申请的内存空间会被 OS 自动释放掉;哪怕会有内存泄漏问题,也会被释放掉。既然结束后都能被 OS 释放掉,那为什么还要担心内存泄漏问题?注意:我们所写的程序都是一个片段,它不能一直跑下去;而真正的软件是 while 循环下去的。
bool CreateHelper(int flags) {
_key = ftok(gpathname.c_str(), gproj_id);
(_key < ) {
();
;
}
(, _key);
_shmid = (_key, _size, flags);
(_shmid < ) {
();
;
}
(, _shmid);
;
}
{
(IPC_CREAT | IPC_EXCL | );
}


