Общая память не обновляется
У меня есть два процесса, которые разговаривают друг с другом, используя сопоставленный файл памяти и именованное событие. Код инициализации одинаков в обоих процессах. Обработка ошибок здесь не показана, но я проверяю все возвращаемые значения.
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 ответ:
Компилятор может оптимизировать код таким образом, чтобы не изменять наблюдаемое поведение. Он делает это путем анализа кода под рукой. Он может свободно выдавать инструкции, которые кэшируют значения в регистрах или переупорядочивают инструкции, если он выводит, что они не связаны. Это безопасно до тех пор, пока компилятор видит все обращения к памяти.
В среде, где память может изменятьсянеобычными способами, компилятор не имеет возможности узнать. Примерами могут служить аппаратные регистры доступа или операции ввода-вывода. места в памяти, где память может изменяться вне программы, которую видит компилятор. Чтобы предотвратить компилятор от каких-либо предположений об объекте,
volatile
ключевое слово доступно на языках C и C++. В результате компилятор не выполняет никаких оптимизаций или инструкций по изменению порядка при обращении к объекту.Чтобы решить вашу проблему, вы должны пометить все данные, находящиеся в общей памяти, как
volatile
. Это гарантирует, что оба процесса всегда будут видеть одни и те же данные. Это также гарантирует, что значение объекта записывается сразу после присвоения.