C++怎么使用共享内存_C++高性能通信教程【加速】

1次阅读

posix共享内存需用shm_open(name以/开头)、ftruncate设大小、mmap配map_shared;写后不立即可见因缓存与重排,须用内存栅栏或锁同步;munmap后指针变野指针,需置nullptr并确保无访问。

C++怎么使用共享内存_C++高性能通信教程【加速】

共享内存本身不提供同步机制,直接用 shmget + shmat 写多进程数据,大概率读到脏数据或崩溃。

怎么安全地创建和映射 POSIX 共享内存(shm_open

linux/macos 推荐用 POSIX API,比 SysV(shmget)更轻、路径可控、支持 fcntl 锁。windowsCreateFileMapping,但跨平台优先选 POSIX。

  • shm_openname 必须以 / 开头,比如 "/my_shm",不能是 "my_shm""./my_shm",否则返回 -1 并设 errno = ENOENT
  • 记得调用 ftruncate 设置大小,否则 mmap 会失败并报 errno = EINVAL
  • 映射时建议加 MAP_SHARED,用 MAP_PRIVATE 改动不会同步到其他进程
int fd = shm_open("/log_buf", O_CREAT | O_RDWR, 0644); ftruncate(fd, 4096); void* ptr = mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

为什么写完不立刻被其他进程看到?——缓存与内存序问题

CPU 和编译器都可能重排写操作,尤其在多核机器上。即使用了 MAP_SHARED,一个进程写了字段 A,另一个进程仍可能读到旧值。

  • 别依赖“写完就可见”,必须显式同步:用 std::atomic_thread_fencec++11+),或 __sync_synchronize()(GCC)
  • 如果共享结构体里有多个字段需原子更新(比如状态+数据),不要单独用 std::atomic<int></int> 包裹每个字段——它们不是事务性的;改用自旋锁或信号量保护整个临界区
  • 避免用 volatile 当同步手段,它不阻止指令重排,也不保证跨线程可见性

常见崩溃点:shmdt / munmap 后继续访问指针

映射解除后,指针变成野指针,但访问不一定立刻段错误——可能读到旧页缓存、也可能触发 SIGSEGV,行为不可预测。

立即学习C++免费学习笔记(深入)”;

  • 解除映射前,确保所有线程已退出对该内存的访问;可配合引用计数或进程间信号通知
  • 解除后立即将指针置为 nullptr,避免后续误用
  • 注意:shm_unlink 不等于立即销毁内存,只要还有进程挂载着,内容就保留;真正释放要等最后一个 shmdtmunmap

共享内存最麻烦的从来不是创建或映射,而是确定哪些字节谁在读、谁在写、什么时候能读、什么时候必须等——没配好同步原语,性能再高也是错的。

text=ZqhQzanResources