4

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

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

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

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

4

3 回答 3

5

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

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

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

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

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

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

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

于 2012-04-17T16:37:22.837 回答
4

您在 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
}

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

于 2012-04-16T15:42:21.400 回答
0

让我们称进程 A 为数据生产者,进程 B 为数据消费者。到目前为止,您有一种机制让进程 A 通知进程 B 新数据已生成。我建议您创建一个反向通知(从 B 到 A),它告诉进程 A 数据已被使用。如果出于性能原因,您不希望进程 A 等待数据被使用,您可以在共享内存中设置一个环形缓冲区。

于 2012-04-16T14:40:31.947 回答