# 7.4 POSIX 共享内存

前面提到的内存映射允许无关进程共享内存区域以执行相应的 IPC，但具有一些缺点，比如它需要在硬盘上创建相应的文件，存在额外的 IO 开销。为了克服这些缺点，提出了 共享内存 API。 使用 POSXI 共享内存一般需要以下步骤：

1. 使用 `shm_open`函数打开一个共享内存对象，此函数返回一个引用该对象的文件描述符。
2. 将上一步获得的文件描述符传入 `mmap`调用并指定 flags 参数中指定 MAP\_SHARED，即可将共享内存对象映射到虚拟地址空间。此文件描述符上可以调用传统 Unix 文件描述符系统调用。

### 创建共享内存对象

`shm_open` 函数创建和打开一个新的共享内存对象或打开一个既有对象，它的参数与 open 函数类似：

```c
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>

/*
@brief	打开一个文件
@param	name		标识出了待创建或待打开的共享内存对象
@param	flags		掩码表，可取：
                	- O_CREAT  对象不存在时创建，若同时指定 O_EXCL，则对象存在时返回错误
                        - O_RDONLY 只读访问
                        - O_RDWR   读写访问
                        - O_TRUNC  将对象截断为 0
@param	mode		标识文件的所有权限，在创建共享内存对象时使用
			仅仅打开一个已有对象需要将其设置为 0
                	- S_IRUSR | S_IWUSR 属主的读写权限
                        - S_IRGRP | S_IWGRP	数组的读写权限
                        - S_IROTH | S_IWOTH	其它的去写权限
@return	成功返回文件描述符，失败返回 -1
*/

int shm_open(const char *name, int oflag, mode_t mode);
```

`shm_open`返回的文件描述符会设置 close-on-exec 标记，因此当程序执行了一个 exec 时文件描述符会被自动关闭。 共享内存对象在创建后其初始长度会被设置为 0，所以在调用 `mmap` 之前调用 `ftruncate`来设置对象的大小。并且在内存映射后继续调用 `ftruncate` 来操作映射内存大小。

### 删除共享内存对象

SUSv3 要求 POSIX 共享内存对象至少具备内核持久性，即它们会持续存在直到被显式删除或系统重启。当不再需要一个共享内存对象时就应该使用`shm_unlink`删除它：

```c
#include <sys/mman.h>

int shm_unlink(const char *name);
```

`shm_unlink`函数会删除通过 name 指定的共享内存对象。删除一个共享内存对象不会影响对象的既有映射（它会保持有效直到相应的进程调用 `munmap` 或终止），但会阻止后续的 `shm_open` 调用打开这个对象。一旦所有进程都解除映射这个对象，对象就会被删除，其中的内容会丢失。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://linuxprogramming.weijun-lin.top/7.-posix-ipc/7.4-posix-gong-xiang-nei-cun.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
