2013-10-28 61 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。這可以確保兩個進程始終能夠看到相同的數據。它還可以確保在分配時立即寫入對象的值。