我见过一个项目,其中进程之间的通信是使用共享内存进行的(例如,在Windows下使用::CreateFileMapping
),并且每当其中一个进程想要通知共享内存中有一些数据可用时,同步使用命名事件的机制通知感兴趣方共享内存的内容发生了变化。
我担心这样一个事实:读取新信息的进程不存在适当的内存栅栏,知道它必须使数据的副本无效,并且一旦被“发布”,就从主内存读取它。生产者过程。
您知道如何使用共享内存在Windows上实现这一目标吗?
修改 只是想在创建文件映射后添加它,进程只使用一次MapViewOfFile()API,对共享数据的每次新修改都使用通过初始调用MapViewOfFile()获得的指针来读取通过共享内存发送的新数据。正确的同步是否要求每次数据在共享内存中发生更改时,读取数据的进程每次都必须创建MapViewOfFile()?
答案 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...
函数编写无锁代码,例如InterlockedExchange
和InterlockedIncrement
。
无论您进行同步,都不需要多次调用MapViewOfFile
。
答案 2 :(得分:0)
让我们调用进程A数据生成器和进程B数据使用者。到目前为止,您有一个进程A的机制来通知进程B已生成新数据。我建议你创建一个反向通知(从B到A),它告诉进程A数据已被消耗。如果出于性能原因,您不希望进程A等待消耗数据,则可以在共享内存中设置ring-buffer。