共享内存——需要同步

Ghi*_*ita 8 c++ windows concurrency shared-memory

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

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

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

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

Ant*_*ams 7

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

进程 A 更改数据并调用SetEvent.

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

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

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

如果您不想使用事件,则可以使用使用 创建的互斥体,或者可以使用和等函数CreateMutex编写无锁代码。Interlocked...InterlockedExchangeInterlockedIncrement

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


Kev*_*son 6

您在 Windows 上寻找共享内存的是 InterlockedExchange 函数。请参阅此处的 msdn 文章。引用了真正重要的部分:

该函数生成完整的内存屏障(或栅栏)以确保内存操作按顺序完成。

这将跨进程运行。我以前使用过它,发现它在共享内存之上实现类似互斥体的结构是 100% 可靠的。

你如何做到这一点就是用“设置”值交换它。如果你得到“清楚”回来,你就拥有了它(它是清楚的),但如果你得到了“设置”回来,那么其他人拥有了它。你循环,在循环之间休眠,等等,直到你“明白”它。基本上是这样的:

#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
}
Run Code Online (Sandbox Code Playgroud)

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