
共享内存队列必须自己管理同步,std::queue 不能直接用
共享内存里放 std::queue 是常见误区——它内部指针指向堆内存,跨进程后地址无效,一读就崩溃。实际得用「无锁 + 固定布局」结构,比如环形缓冲区(ring buffer),所有字段都存于共享内存段内,不依赖堆分配。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 用
boost::interprocess::managed_shared_memory创建共享段,显式控制生命周期 - 队列结构体所有成员必须是 POD 类型(不含虚函数、引用、非静态成员函数),字段按需对齐(
alignas(64)防伪共享) - 头尾索引用
std::atomic<size_t></size_t>,但注意:x86 上std::atomic在共享内存中需用BOOST_INTERPROCESS_USE_GENERIC_EMULATION宏确保跨进程可见性 - 避免
std::string或std::vector,改用固定长度数组或boost::interprocess::basic_string
boost::interprocess::message_queue 为什么不适合低延迟场景?
它底层基于 POSIX message queue 或 Windows I/O completion port,有内核态切换开销,典型延迟在 5–20 μs 级别,且吞吐受系统消息大小限制(Linux 默认 /proc/sys/fs/mqueue/msgsize_max 是 8192 字节)。真要 sub-μs 级,必须绕过内核。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 用
boost::interprocess::mapped_file或shm_open+mmap手动映射,控制页锁定(mlock)防 swap - 生产者/消费者各自缓存本地索引副本,只在关键点原子读写共享头尾,减少 cache line 争用
- 禁用编译器重排序:
std::atomic_thread_fence(std::memory_order_acquire)和std::atomic_thread_fence(std::memory_order_release)必须成对出现
Ring buffer 的 wrap-around 处理容易引发 ABA 问题
当生产者快速写满又清空,头尾索引可能“绕回”到相同数值,但语义已不同。单纯比较 head == tail 无法区分空/满,而用额外标志位又破坏无锁设计。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 预留一个槽位不使用(即容量设为 N-1),用
(tail + 1) % capacity == head判满,head == tail判空——简单可靠 - 索引类型必须足够宽(如
uint64_t),避免计数溢出导致误判;32 位在 1G 次操作后就可能翻转 - 不要用
std::atomic<uint32_t>::compare_exchange_weak</uint32_t>直接更新索引,先 load 当前值,再计算新值,最后 CAS,否则并发下会丢数据
Windows 下 CreateFileMapping 映射失败的三个隐蔽原因
错误码常是 ERROR_INVALID_PARAMETER 或静默失败,不是权限或路径问题,而是映射选项没配对。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 创建时必须指定
SEC_COMMIT标志,否则MapViewOfFile可能返回 NULL(尤其大内存段) - 映射视图大小必须 ≤ 文件映射对象大小,且
MapViewOfFile的dwNumberOfBytesToMap参数不能为 0 - 多进程首次访问前,需确保所有进程都调用
FlushViewOfFile后再退出,否则未刷回的数据在另一进程里不可见
std::atomic_signal_fence 和 mfence 检查汇编输出。










