Общая память не обновляется


У меня есть два процесса, которые разговаривают друг с другом, используя сопоставленный файл памяти и именованное событие. Код инициализации одинаков в обоих процессах. Обработка ошибок здесь не показана, но я проверяю все возвращаемые значения.

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. На следующей итерации он может читать обновленное значение. Обе программы находятся в отладочной конфигурации, без оптимизации. Они работают на многоядерном компьютере под управлением Windows 7. Доступ к общей памяти не синхронизируется, так как транзакции чтения / записи инициируются командой пользователя и сериализуются.

Как я могу изменить эту программу, чтобы получить последнее обновленное значение на стороне клиента?

1 2

1 ответ:

Компилятор может оптимизировать код таким образом, чтобы не изменять наблюдаемое поведение. Он делает это путем анализа кода под рукой. Он может свободно выдавать инструкции, которые кэшируют значения в регистрах или переупорядочивают инструкции, если он выводит, что они не связаны. Это безопасно до тех пор, пока компилятор видит все обращения к памяти.

В среде, где память может изменятьсянеобычными способами, компилятор не имеет возможности узнать. Примерами могут служить аппаратные регистры доступа или операции ввода-вывода. места в памяти, где память может изменяться вне программы, которую видит компилятор. Чтобы предотвратить компилятор от каких-либо предположений об объекте,volatile ключевое слово доступно на языках C и C++. В результате компилятор не выполняет никаких оптимизаций или инструкций по изменению порядка при обращении к объекту.

Чтобы решить вашу проблему, вы должны пометить все данные, находящиеся в общей памяти, как volatile. Это гарантирует, что оба процесса всегда будут видеть одни и те же данные. Это также гарантирует, что значение объекта записывается сразу после присвоения.