尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Linux--进程通讯--POSIX共享内存

Linux--进程通讯--POSIX共享内存 一、POSIX共享内存共享内存是最快的 IPC进程间通信形式一旦映射到进程地址空间数据传递不再涉及内核进程可以直接读写内存。特点速度最快无内核拷贝进程直接访问同一块物理内存需要同步必须配合信号量使用否则会出现数据竞争文件风格接口用 shm_open() 创建、 mmap() 映射像操作文件一样内核持久对象不会随进程退出自动销毁需要手动删除 shm_unlink() 或 rm /dev/shm/xxx 与 System V 共享内存的区别System V使用 shmget() / shmat() / shmdt() 接口复杂POSIX使用 shm_open() / mmap() / munmap() 接口更简洁符合“一切皆文件”思想新项目推荐使用 POSIX 共享内存二、共享内存示意图管道、消息队列的数据都需要经过内核拷贝而共享内存不需要进程 A 的虚拟地址通过页表指向一块物理内存进程 B 的虚拟地址也通过页表指向同一块物理内存两个进程直接读写同一块物理内存无内核拷贝A 写完后 B 立即可见⚠️ 注意共享内存本身不提供同步机制必须配合信号量使用否则会出现数据竞争。三、核心函数POSIX 共享内存的操作流程像操作文件 shm_open → ftruncate → mmap → munmap → close → shm_unlinkshm_open — 创建/打开共享内存对象作用创建或打开共享内存对象返回文件描述符类似 open() #includesys/mman.h#includesys/stat.h#includefcntl.hintshm_open(constchar*name,intoflag,mode_tmode);name 必须以 / 开头如 /myshm oflag 常用 O_CREAT | O_RDWR 创建读写mode 权限如 0644返回值成功返回文件描述符失败返回 -1示例intfdshm_open(/myshm,O_CREAT|O_RDWR,0644);if(fd-1){perror(shm_open);}ftruncate — 设置共享内存大小作用设置共享内存对象的大小必须在 mmap 之前调用新创建的对象默认大小为 0。#includeunistd.h#includesys/types.hintftruncate(intfd,off_tlength);fd shm_open 返回的文件描述符length 要设置的大小字节返回值成功返回 0 失败返回 -1示例if(ftruncate(fd,4096)-1){perror(ftruncate);}mmap — 映射到进程地址空间作用将共享内存对象映射到进程的虚拟地址空间之后可以直接通过返回的地址读写共享内存。#includesys/mman.hvoid*mmap(void*addr,size_tlength,intprot,intflags,intfd,off_toffset);addr 填 NULL 让系统自动分配地址length 映射大小和 ftruncate 设置的大小一致prot 权限常用 PROT_READ | PROT_WRITEflags 填 MAP_SHARED 共享映射fd shm_open 返回的文件描述符offset 填 0返回值成功返回映射地址失败返回 MAP_FAILED示例char*addrmmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(addrMAP_FAILED){perror(mmap);}munmap — 解除映射作用解除 mmap 建立的映射关系之后不能再通过该地址访问共享内存。#includesys/mman.hintmunmap(void*addr,size_tlength);addr mmap 返回的虚拟地址length 映射大小返回值成功返回 0 失败返回 -1示例if(munmap(addr,4096)-1){perror(munmap);}shm_unlink — 删除共享内存对象作用从系统中删除共享内存对象对象被标记为待删除等所有进程解除映射后才真正销毁。#includesys/mman.hintshm_unlink(constchar*name);name 共享内存对象名和 shm_open 一致返回值成功返回 0 失败返回 -1示例if(shm_unlink(/myshm)-1){perror(shm_unlink);}close — 关闭文件描述符作用关闭 shm_open 返回的文件描述符但不会删除共享内存对象对象仍存在于系统中。#includeunistd.hintclose(intfd);fd shm_open 返回的文件描述符返回值成功返回 0 失败返回 -1示例close(fd);四、完整使用流程创建 shm_open → 设置 ftruncate → 映射 mmap → 使用共享内存 → 解除映射munmap → 关闭文件描述 close → 删除共享对象 shm_unlink最后一步可选通常由最后一个进程执行// 1. 创建/打开共享内存对象intfdshm_open(/myshm,O_CREAT|O_RDWR,0644);// 2. 设置大小ftruncate(fd,4096);// 3. 映射到地址空间char*addrmmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);// 4. 使用共享内存读写 addr// 5. 解除映射munmap(addr,4096);// 6. 关闭文件描述符close(fd);// 7. 删除共享内存对象可选通常由最后一个进程执行shm_unlink(/myshm);注意事项• 编译链接需要加 -lrt 链接实时库• 必须先 ftruncate新创建的共享内存大小为 0必须先设置大小再 mmap• flags 必须用 MAP_SHARED如果用 MAP_PRIVATE修改不会写回其他进程不可见• shm_unlink 时机应在最后一个进程使用完后调用过早删除可能影响其他进程• 需要同步多进程同时读写时必须配合信号量使用五、 与信号量配合使用信号量类型选择命名信号量有名字如 /mysem存在于系统中sem_open() / sem_close() 用于无亲缘关系进程间无名信号量只有变量sem_init() / sem_destroy() 常用于线程间或有亲缘关系进程对于共享内存通常用于无亲缘关系进程推荐使用命名信号量。命名信号量基本操作创建/打开sem_open()创建或打开一个命名信号量P 操作加锁sem_wait() 信号量值减 1如果为 0 则阻塞V 操作解锁sem_post() 信号量值加 1唤醒等待进程关闭sem_close()关闭信号量不删除删除sem_unlink() 从系统中删除信号量六、POSIX vs System V 共享内存POSIX 共享内存和 System V 共享内存的底层原理相同都是将同一块物理内存映射到多个进程的虚拟地址空间。两者的主要区别在于接口设计、标识方式和操作风格。核心区别POSIX 共享内存采用文件操作风格使用 shm_open() 创建、mmap() 映射、shm_unlink() 删除接口简洁直观对象通过文件名如 /myshm标识支持动态调整大小。System V 共享内存则使用专属系统调用通过 shmget() 创建、shmat() 映射、shmctl() 删除接口复杂对象通过 key_t 和整数 ID 标识大小在创建时固定。管理方式差异POSIX 共享内存对象位于 /dev/shm/ 目录可以用 ls 和 rm 命令查看和删除。System V 共享内存则需要使用 ipcs -m 查看、ipcrm -m 删除。选型建议新项目推荐使用 POSIX 共享内存接口更简洁符合 Linux “一切皆文件” 的设计思想。
返回列表