共享内存 - 需要同步
Shared memory - need for synchronization
我见过一个项目,其中进程之间的通信是使用共享内存进行的(例如,在Windows下使用::CreateFileMapping
),并且每次其中一个进程想要通知共享内存中某些数据可用时,使用命名事件的同步机制通知相关方共享内存的内容发生了变化。
我担心的是,读取新信息的进程不存在适当的内存围栏,以了解它必须使其数据副本无效,并在生产者进程"发布"数据后从主内存中读取数据。
您知道如何使用共享内存在Windows上完成此操作吗?
编辑只是想补充一点,在创建文件映射后,进程仅使用 MapViewOfFile() API 一次,并且对共享数据的每次新修改都使用初始调用 MapViewOfFile() 获得的指针来读取通过共享内存发送的新数据。正确的同步是否要求每次共享内存中的数据更改时,读取数据的进程每次都必须创建 MapViewOfFile() ?
如果使用 Windows 命名事件来发出更改信号,那么一切应该都正常。
进程 A 更改数据并调用SetEvent
。
进程 B 使用 WaitForSingleObject
或类似方式等待事件,并看到它已设置。
然后,进程 B 读取数据。 WaitForSingleObject
包含所有必要的同步,以确保进程 B 读取进程 A 在调用 SetEvent
之前所做的更改。
当然,如果在调用 SetEvent
后对数据进行了任何更改,则当进程 B 读取数据时,这些更改可能会也可能不会显示。
如果您不想使用事件,则可以使用使用CreateMutex
创建的互斥体,也可以使用InterlockedExchange
和InterlockedIncrement
等Interlocked...
函数编写无锁代码。
无论执行同步如何,都不需要多次调用MapViewOfFile
。
你在Windows上寻找共享内存的是InterlockedExchange函数。 请参阅此处的 msdn 文章。 引用了真正重要的部分:
此函数生成完整的内存屏障(或围栏)以确保 内存操作按顺序完成。
这将跨进程运行。 我以前使用过它,发现它在共享内存之上实现类似互斥体的结构是 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
}
如上所述,循环直到你"得到"它。
我们将进程 A 称为数据生产者,将进程 B 称为数据使用者。到目前为止,流程 A 有一种机制来通知进程 B 已生成新数据。我建议您创建一个反向通知(从 B 到 A),告诉进程 A 数据已被消耗。如果出于性能原因,您不希望进程 A 等待数据被使用,则可以在共享内存中设置环形缓冲区。
- 将字符串存储在c++中的稳定内存中
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- Win32编译器选项和内存分配
- 当vector是tje全局变量时,c++中vector的内存管理
- 带内存和隔离功能的SQLite
- 与原子内存围栏同步C++
- c++ 读取时同步共享内存
- 特定共享内存写操作(MPI)的同步
- boost::OSX 上 32 位和 64 位程序之间共享内存中的进程间同步机制(互斥体、条件)
- 如何在不同步的情况下创建线程本地内存
- 共享内存IPC同步(无锁)
- “std::mutex”和“std::lock”是否保证处理器间代码中的内存同步
- POSIX 跨进程共享内存同步 C++/C++11
- 共享内存 - 需要同步
- 使用获取-释放内存排序的传递同步
- 共享内存与信号量同步
- 共享内存C++读写同步
- c++和c#之间的共享内存同步
- 同步对已分配内存的访问
- CUDA:将全局内存写入和读取与计算能力同步 1.1