【发布时间】:2014-04-08 02:08:12
【问题描述】:
考虑以下场景:
要求:
- Intel x64 服务器(多个 CPU 插槽 => NUMA)
- Ubuntu 12,GCC 4.6
- 两个进程通过(命名的)共享内存共享大量数据
- 经典的生产者-消费者场景
- 内存排列在一个循环缓冲区中(有 M 个元素)
程序序列(伪代码):
流程 A(生产者):
int bufferPos = 0;
while( true )
{
if( isBufferEmpty( bufferPos ) )
{
writeData( bufferPos );
setBufferFull( bufferPos );
bufferPos = ( bufferPos + 1 ) % M;
}
}
流程 B(消费者):
int bufferPos = 0;
while( true )
{
if( isBufferFull( bufferPos ) )
{
readData( bufferPos );
setBufferEmpty( bufferPos );
bufferPos = ( bufferPos + 1 ) % M;
}
}
现在是一个古老的问题:如何有效地同步它们!?
- 使用互斥锁保护每个读/写访问
- 引入“宽限期”,以允许完成写入:读取缓冲区 N 中的数据,此时缓冲区 (N+3) 已被标记为已满(危险,但似乎有效...)
- ?!?
理想情况下,我想要一些类似于内存屏障的东西,以保证所有先前的读/写在所有 CPU 上都是可见的,类似于:
writeData( i );
MemoryBarrier();
//All data written and visible, set flag
setBufferFull( i );
这样,我只需要监视缓冲区标志,然后就可以安全地读取大数据块。
一般来说,我正在寻找与 Preshing 在此处描述的获取/释放栅栏类似的东西:
http://preshing.com/20130922/acquire-and-release-fences/
(如果我理解正确的话,C++11 原子仅适用于单个进程的线程,而不适用于多个进程。)
但是 GCC 自己的内存屏障(__sync_synchronize 与编译器屏障 asm volatile( "" ::: "memory" ) 可以肯定)似乎没有按预期工作,因为在屏障之后写入变得可见,当我预计它们会完成时。
任何帮助将不胜感激......
顺便说一句:在 Windows 下,使用 volatile 变量(微软特有的行为)可以正常工作...
【问题讨论】:
标签: c++ synchronization ipc shared-memory lock-free