我有两个进程,使用内存映射文件和命名事件相互通信。两个进程中的初始化代码相同。此处未显示错误处理,但我检查了所有返回值。
HANDLE m_hFileMapping;
LPVOID m_pViewOfFile;
int* m_pDataPtr;
HANDLE m_hEventDone;
m_hFileMapping = CreateFileMapping(
INVALID_HANDLE_VALUE, // system paging file
NULL, // security attributes
PAGE_READWRITE, // protection
0, // high-order DWORD of size
MEMORY_MAPPED_FILE_SIZE, // low-order DWORD of size (4096)
MEMORY_MAPPED_FILE_NAME); // name (the same for both processes)
m_pViewOfFile = MapViewOfFile(
m_hFileMapping, // handle to file-mapping object
FILE_MAP_ALL_ACCESS, // desired access
0,
0,
0); // map all file
m_pDataPtr = (int*)m_pViewOfFile;
m_hEventDone = CreateEvent(NULL, FALSE, FALSE, EVENT_NAME_COMMAND_DONE); // the same name in both processes
服务器进程更新共享内存并设置事件:
*m_pDataPtr = some_value;
SetEvent(m_hEventDone);
客户端进程等待m_hEventDone
。一旦设置了事件,它就会读取内存:
if ( WaitForSingleObject(m_hEventDone, TIMEOUT_INTERVAL) != WAIT_OBJECT_0 )
{
// handle error and return
}
int result = *m_pDataPtr;
有时,客户端进程会从m_pDataPtr
读取旧的(上一个)值。在下一次迭代中,它可以读取更新的值。这两个程序都在Debug配置中,没有优化。它们运行在Windows 7多核计算机上。对同步内存的访问不同步,因为读/写事务由用户命令启动并序列化。
如何更改此程序以获取客户端的最新更新值?
答案 0 :(得分:2)
编译器可以以不改变观察到的行为的方式优化代码。它是通过分析手头的代码来实现的。如果它推断它们是不相关的,则可以自由发出缓存寄存器中的值或重新排序指令的指令。只要编译器看到对内存的所有访问,这都是安全的。
在内存可以以异常方式更改的环境中,编译器无法知道。例如硬件寄存器访问或I / O映射的内存位置,其中内存可以在编译器看到的程序之外进行更改。为了防止编译器对对象做出任何假设,{C}和C ++中的volatile
关键字可用。结果是编译器在访问对象时不会执行任何优化或重新排序指令。
要解决您的问题,您必须将驻留在共享内存中的所有数据标记为volatile
。这可以保证两个进程始终看到相同的数据。它还确保在分配时立即写入对象的值。