共享内存 - 需要同步

时间:2012-04-16 14:06:24

标签: c++ windows concurrency shared-memory

我见过一个项目,其中进程之间的通信是使用共享内存进行的(例如,在Windows下使用::CreateFileMapping),并且每当其中一个进程想要通知共享内存中有一些数据可用时,同步使用命名事件的机制通知感兴趣方共享内存的内容发生了变化。

我担心这样一个事实:读取新信息的进程不存在适当的内存栅栏,知道它必须使数据的副本无效,并且一旦被“发布”,就从主内存读取它。生产者过程。

您知道如何使用共享内存在Windows上实现这一目标吗?

修改 只是想在创建文件映射后添加它,进程只使用一次MapViewOfFile()API,对共享数据的每次新修改都使用通过初始调用MapViewOfFile()获得的指针来读取通过共享内存发送的新数据。正确的同步是否要求每次数据在共享内存中发生更改时,读取数据的进程每次都必须创建MapViewOfFile()?

3 个答案:

答案 0 :(得分:4)

您在Windows上寻找共享内存的是InterlockedExchange功能。请参阅msdn article here。引用的真正重要部分是:

  

此功能可生成完整的内存屏障(或栅栏)以确保   内存操作按顺序完成。

这将起到跨进程的作用。之前我曾经使用它,并发现它在共享内存之上实现类似互斥体的构造是100%可靠的。

你是如何做到这一点的,你用“set”值交换它。如果你得到“清醒”,你就可以了(很明显),但是如果你得到“设定”,那么其他人就有了它。你循环,在循环之间休眠等,直到你“得到”它。基本上这个:

#define LOCK_SET 1
#define LOCK_CLEAR 0

int* lock_location = LOCK_LOCATION; // ensure this is in shared memory
if (InterlockedExchange(lock_location, LOCK_SET) == LOCK_CLEAR)
{
    return true; // got the lock
}
else
{
    return false; // didn't get the lock
}

如上所述,循环直到你“得到”它。

答案 1 :(得分:4)

如果您使用Windows命名事件进行信号更改,那么一切都应该没问题。

流程A更改数据并调用SetEvent

进程B使用WaitForSingleObject或类似内容等待事件,并看到它已设置。

进程B然后读取数据。 WaitForSingleObject包含所有必要的同步,以确保进程B读取在调用SetEvent之前进程A所做的更改。

当然,如果您在调用SetEvent之后对数据进行了任何更改,那么当进程B读取数据时,这些可能会也可能不会显示。

如果您不想使用事件,可以使用通过CreateMutex创建的互斥锁,也可以使用Interlocked...函数编写无锁代码,例如InterlockedExchangeInterlockedIncrement

无论您进行同步,都不需要多次调用MapViewOfFile

答案 2 :(得分:0)

让我们调用进程A数据生成器和进程B数据使用者。到目前为止,您有一个进程A的机制来通知进程B已生成新数据。我建议你创建一个反向通知(从B到A),它告诉进程A数据已被消耗。如果出于性能原因,您不希望进程A等待消耗数据,则可以在共享内存中设置ring-buffer