Примечание: я не эксперт по этой теме, некоторые из моих высказываний "то, что я слышал в Интернете", но я думаю, что csan все еще проясняет некоторые заблуждения.
[править] В общем, я бы полагался на особенности платформы, такие как атомарные чтения x86 и отсутствие OOOX, только в изолированных локальных оптимизациях, которые защищены #ifdef
проверкой целевой платформы, в идеале сопровождаемойпортативным решением на пути #else
.
На что обращать внимание
- атомарность операций чтения / записи
- переупорядочение из-за оптимизаций компилятора (это включает в себя другой видимый порядокдругим потоком из-за простого кеширования регистра)
- неправильное выполнение в CPU
Возможные заблуждения
1. Насколько я понимаю, поскольку функция защищена и компилятор не может переупорядочить ее внутри.
[edit] Чтобы уточнить: _ReadWriteBarrier
обеспечивает защиту от переупорядочения команд, однако вы должны выходить за рамки этой функции._ReadWriteBarrier
было исправлено в VS 2010, чтобы сделать это, более ранние версии могут быть сломаны (в зависимости от оптимизации, которую они фактически делают).
Оптимизация не ограничивается функциями.Существует несколько механизмов (автоматическое встраивание, генерация временного кода канала), которые охватывают функции и даже блоки компиляции (и могут обеспечить гораздо более существенную оптимизацию, чем кэширование регистров с малой областью действия).
2. Visual C ++ [...] выполняет нестабильное чтение и запись атомарных загрузок и хранилищ,
Где вы это нашли? MSDN говорит, что за пределами стандарта будут установлены барьеры памяти для чтения и записи, без гарантии атомарного чтения.
[edit] Обратите внимание, что C #, Java, Delphiи т. д. имеют разные значения памяти и могут давать разные гарантии.
3. обычные загрузки и хранилища в любом случае должны быть атомными на x86, верно?
Нет, они не.Чтение без выравнивания не является атомарным.Они оказываются атомными, если они хорошо выровнены - на этот факт я бы не стал полагаться, если бы он не был изолирован и легко заменялся.В противном случае ваше «simpificaiton fo x86» становится привязкой к этой цели.
[edit] Произойдет несогласованное чтение:
char * c = new char[sizeof(int)+1];
load(*(int *)c); // allowed by standard to be unaligned
load(*(int *)(c+1)); // unaligned with most allocators
#pragma pack(push,1)
struct
{
char c;
int i;
} foo;
load(foo.i); // caller said so
#pragma pack(pop)
Это, конечно, все академические, если выпомните, что параметр должен быть выровнен, и вы управляете всем кодом.Я бы больше не писал такой код, потому что меня часто кусала лень прошлого.
4. Простая загрузка приобрела семантику на x86, обычное хранилищеимеет семантику релиза
Нет. Процессоры x86 не используют неупорядоченное выполнение (или, скорее, никакого видимого OOOX - я думаю), но это не мешает оптимизатору переупорядочивать инструкции.
5. _ReadBarrier / _WriteBarrier / _ReadWriteBarrier делают всю магию, которой они не делают - они просто предотвращают изменение порядка в оптимизаторе.MSDN, наконец, сделал это большим плохим предупреждением для VS2010, но эта информация, очевидно, относится и к предыдущим версиям .
Теперь к вашему вопросу.
Я предполагаю, что цель фрагмента кода - передать любую переменную N и загрузить ее (атомарно?). Простым выбором будет чтение с блокировкой или (в Visual C ++ 2005 и более поздних версиях) энергозависимое чтение.
В противном случае вам потребуется барьер для компилятора и процессора перед чтением, в кабинете VC ++ это будет:
int load(int& var)
{
// force Optimizer to complete all memory writes:
// (Note that this had issues before VC++ 2010)
_WriteBarrier();
// force CPU to settle all pending read/writes, and not to start new ones:
MemoryBarrier();
// now, read.
int value = var;
return value;
}
Нет, что _WriteBarrier
имеет второе предупреждение в MSDN:* В предыдущих версиях компилятора Visual C ++ функции _ReadWriteBarrier и _WriteBarrier применялись только локально и не влияли на функции в дереве вызовов.Эти функции теперь выполняются вплоть до дерева вызовов. *
I Надеюсь , что правильно.stackoverflowers, пожалуйста, поправьте меня, если я ошибаюсь.