Я прочитал стандарт C ++ (n4713) § 32.6.1 3:
Операции без блокировок также должны быть безадресными. То есть атомарные операции в одном и том же месте памяти через два разных адреса будут взаимодействовать атомарно. Реализация не должна зависеть от состояния каждого процесса. Это ограничение позволяет осуществлять обмен данными посредством памяти, которая отображается на процесс более одного раза, и посредством памяти, которая используется совместно двумя процессами.
Похоже, что можно выполнить атомарную операцию без блокировки в том же месте памяти. Интересно, как это можно сделать.
Скажем, у меня есть именованный сегмент разделяемой памяти в Linux (через shm_open () и mmap ()). Как, например, выполнить операцию без блокировки на первых 4 байтах сегмента разделяемой памяти?
Сначала я подумал, что могу просто reinterpret_cast
указать указатель на std::atomic<int32_t>*
. Но потом я прочитал это. Во-первых, он указывает на то, что std :: atomic может не иметь того же размера T или выравнивания:
Когда мы разрабатывали атомарные модели C ++ 11, у меня было неправильное представление о том, что можно полупортативно применять атомарные операции к данным, не объявленным атомарными, используя такой код, как
int x; reinterpret_cast<atomic<int>&>(x).fetch_add(1);
Это явно не сработает, если представления atomic и int различаются или их выравнивание различается. Но я знаю, что это не проблема для платформ, которые меня волнуют. И на практике я могу легко проверить наличие проблемы, проверив во время компиляции соответствие размеров и выравнивания.
Но в данном случае меня устраивает, потому что я использую общую память на одном компьютере, и приведение указателя к двум разным процессам «захватит» одно и то же место. Однако в статье говорится, что компилятор может не рассматривать приведенный указатель как указатель на атомарный тип:
Однако не гарантируется, что это будет надежно даже на платформах, на которых можно было бы ожидать, что это будет работать, поскольку это может запутать анализ псевдонимов на основе типов в компиляторе. Компилятор может предположить, что int также не доступен как
atomic<int>
. (См. 3.10, [Basic.lval], последний абзац.)
Любой вклад приветствуется!