2013-10-28 62 views
2

我有两个进程,使用内存映射文件和命名事件相互交谈。初始化代码在两个进程中都是相同的。这里没有显示错误处理,但我检查了所有的返回值。共享内存不更新

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 

Server进程更新共享内存,并设置事件:

*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旧的(以前的)值。在下一次迭代中,它可以读取更新的值。这两个程序都在调试配置中,没有优化。他们运行在Windows 7多核计算机上。访问共享内存不同步,因为读/写事务是由用户命令启动并序列化的。

如何更改此程序以获取客户端的最新更新值?

+4

'volatile'将阻止编译器生成缓存变量值或从缓存读取它的代码。相反,该值是从内存中读取的。 – IInspectable

+0

@IInspectable:定义指针作为volatile解决了问题。发布这个答案,我会接受它。 –

回答

2

编译器可以以不改变观察到的行为的方式优化代码。它通过分析手头的代码来实现。如果它推断它们是不相关的,那么它可以自由发出缓存寄存器值或重新排序指令的值的指令。只要编译器看到所有对内存的访问,这是安全的。

在内存可以改变的环境中,出现异常的方式,编译器无法知道。例如硬件寄存器访问或I/O映射的内存位置,其中内存可以在编译器看到的程序之外进行更改。为了防止编译器对关于对象的任何假设,在C和C++中提供关键字volatile。其结果是编译器在访问对象时不会执行任何优化或重新排序指令。

要解决您的问题,您必须将驻留在共享内存中的所有数据标记为volatile。这可以确保两个进程始终能够看到相同的数据。它还可以确保在分配时立即写入对象的值。