System V共享内存 我们把进程间通信叫做进程IPC Inter Process Communication1.匿名命名管道 基于文件 基于已有的文件内核代码进行当前改良本质是在复用代码2.System V进程间通信同一台主机这里写目录标题共享内存原理理解是什么接口shmget创建或获取共享内存为什么 key 需要由用户提供如何生成 keyftok生成 System V IPC key共享内存的查看与删除查看共享内存删除共享内存key 与 shmid 的区别如何把共享内存挂接到虚拟地址空间共享内存原理共享内存的核心思想是让不同的进程看到同一份物理内存资源。具体来说操作系统将同一块物理内存区域分别映射到多个进程各自的虚拟地址空间中。每个进程都会获得一个指向该共享内存区域的起始虚拟地址。通过这种方式多个进程可以直接读写同一块物理内存从而实现高效的数据共享。图共享内存原理示意图技术细节在同一台主机上物理内存是唯一的。每个进程都有自己独立的task_struct和虚拟地址空间。虽然不同进程的虚拟地址空间是隔离的但通过操作系统的页表机制可以将它们各自的虚拟地址映射到同一块物理内存页上。这样进程 A 和进程 B 访问各自虚拟地址空间中的某个地址时实际上读写的是同一块物理内存。理解可以从以下几个层面理解共享内存映射到共享区共享内存被映射到进程虚拟地址空间的“共享区”而非私有数据区如栈、堆。类比动态库其原理类似于动态链接库.so/.dll都是将一段内存映射到多个进程的地址空间。但共享内存更“轻量”它只提供一块原始的内存区域不包含代码逻辑。内存更轻量它只提供一块原始的内存区域不包含代码逻辑。操作系统管理系统中可能存在多块共享内存因此需要被操作系统统一管理。遵循先描述再组织的原则内核会为每块共享内存维护一个管理结构体如struct shmid_ds。共享内存 管理结构体 实际的内存块。使用步骤使用共享内存通常遵循以下五个步骤创建申请一块指定大小的共享内存。关联挂接将共享内存映射到本进程的虚拟地址空间。使用通过获得的指针进行读写操作。去关联分离解除本进程与共享内存的映射关系。释放删除当所有进程都分离后可销毁该共享内存。是什么共享内存Shared Memory是一种进程间通信IPC机制。它允许多个进程通过将同一块物理内存映射到各自虚拟地址空间的方式直接访问同一片内存区域。这是最快的一种 IPC 方式因为数据不需要在进程间复制而是直接在内存中共享。接口共享内存的创建和管理必须由操作系统完成因为进程通过new或malloc分配的空间位于其私有堆上具有进程独立性无法直接与其他进程共享。因此操作系统提供了一系列系统调用来实现共享内存。shmget创建或获取共享内存shmget是创建或获取共享内存段的关键系统调用。函数原型intshmget(key_tkey,size_tsize,intshmflg);参数说明key (key_t)共享内存的键值key用于在内核中唯一标识一个共享内存段。多个进程通过相同的 key 来访问同一块共享内存。size (size_t)要创建的共享内存大小以字节为单位。必须是系统页大小通常为 4096 字节的整数倍。shmflg (int)创建标志和权限的组合通常使用宏定义。返回值成功返回一个非负整数即共享内存标识符shmid用于后续操作。失败返回-1。常用标志shmflgIPC_CREAT如果 key 对应的共享内存不存在则创建它如果已存在则获取其标识符。IPC_EXCL必须与IPC_CREAT一起使用IPC_CREAT | IPC_EXCL。表示“独占创建”——仅当 key 对应的共享内存不存在时才创建如果已存在则调用失败。这常用于确保创建的是全新的共享内存段。权限位通常需要与上述标志按位或|一个八进制权限值例如0666表示所有用户可读写。如果不指定创建的共享内存可能没有访问权限。图shmget 函数示意图为什么 key 需要由用户提供操作系统无法自动为需要通信的进程分配合适的 key。因为进程独立性操作系统创建的 key 是进程 A 的私有数据无法直接传递给进程 B。通信意图未知操作系统无法预知哪些进程需要通信。因此key 必须由用户程序员约定并传递给双方进程。双方进程使用相同的 key 调用shmget操作系统内核会根据这个 key 找到或创建对应的共享内存结构体从而让两个进程“看到”同一块物理内存。图用户约定 key 的必要性如何生成 keykey_t本质是一个整数。你可以手动指定一个固定值如0x1234但更推荐使用ftok函数动态生成以避免冲突。ftok生成 System V IPC keyftok根据文件路径和一个项目标识符生成一个唯一的 key。函数原型key_tftok(constchar*pathname,intproj_id);参数说明pathname (const char*)一个已存在文件的路径任何文件均可。函数会读取该文件的 inode 号。proj_id (int)项目标识符一个非零的整数通常用字符的 ASCII 码如a。返回值成功返回生成的key_t值。失败返回(key_t) -1。函数内部会将文件的 inode 号和 proj_id 进行运算生成一个唯一的 key。只要两个进程使用相同的pathname和proj_id就能得到相同的 key。图ftok 函数生成 key 的原理共享内存的查看与删除查看共享内存使用ipcs -m命令可以查看系统中当前存在的所有 System V 共享内存段。删除共享内存共享内存的生命周期随内核除非显式删除或系统重启否则会一直存在。1. 命令行删除ipcrm-mshmid其中shmid是shmget返回的共享内存标识符。2. 代码删除使用shmctlshmctl是一个多功能控制函数可用于删除共享内存或获取/设置其属性。函数原型intshmctl(intshmid,intcmd,structshmid_ds*buf);参数说明shmid (int)要操作的共享内存标识符。cmd (int)控制命令。buf (struct shmid_ds *)指向shmid_ds结构体的指针用于获取或设置属性。删除时可设为NULL。常用命令cmdIPC_RMID立即删除共享内存段。即使仍有进程与之关联该段也会被标记为“待删除”在所有进程都分离detach后内核会真正回收资源。调用时buf参数可设为NULL。图shmctl 函数示意图key 与 shmid 的区别key在内核中唯一标识共享内存段。由用户约定用于shmget的创建/获取。shmid在用户空间使用的共享内存句柄。由shmget返回用于后续的shmat、shmdt、shmctl等操作。类比key 类似于文件的 inode 号唯一标识shmid 类似于文件描述符 fd用户使用的句柄。删除时使用的是 shmid而不是 key。如何把共享内存挂接到虚拟地址空间共享内存创建后需要将其“挂接”Attach到进程的虚拟地址空间进程才能访问它。这通过shmat系统调用实现。函数原型void*shmat(intshmid,constvoid*shmaddr,intshmflg);参数说明shmid要连接的共享内存标识符即shmget的返回值。shmaddr指定挂接的起始虚拟地址。通常设为NULL由系统自动选择合适的地址。shmflg挂接标志例如设置只读SHM_RDONLY等。一般传0表示可读写。返回值成功返回挂接后共享内存段在进程虚拟地址空间中的起始地址void*类型。失败返回(void*) -1。这个返回值类似于malloc返回的堆内存地址进程后续通过该指针访问共享内存。当进程不再需要访问共享内存时应调用shmdt进行“去挂接”Detach。函数原型intshmdt(constvoid*shmaddr);参数说明shmaddr要断开连接的共享内存起始地址即shmat的返回值。返回值成功返回0。失败返回-1。注意shmdt只是断开进程与共享内存的映射关系并不会删除共享内存本身。删除共享内存需要使用shmctl命令IPC_RMID。