Связано: Spinlock with XCHG объясняет, почему вам не нужно xchg
для снятия блокировки в x86 asm, просто инструкция сохранения.
Но в C ++ , вам нужно что-то более сильное, чем простая gf = 0;
в простой переменной long gf
. Модель памяти C / C ++ (для обычных переменных) очень слабо упорядоченный, даже при компиляции для сильно упорядоченного x86, потому что это важно для оптимизации.
Для правильного снятия блокировки вам потребуется хранилище релизов, не позволяющее операциям в критической секции вытекать из критической секции путем переупорядочения во время компиляции или выполнения с хранилищем gf=0
. http://preshing.com/20120913/acquire-and-release-semantics/.
Поскольку вы используете long gf
, а не volatile long gf
, и вы не используете барьер памяти компилятора, ничто в вашем коде не помешает переупорядочению во время компиляции. (Хранилища x86 asm имеют семантику релиза, поэтому нам нужно беспокоиться только о переупорядочении во время компиляции.) http://preshing.com/20120625/memory-ordering-at-compile-time/
Мы получаем все, что нам нужно, как можно дешевле, используя std::atomic<long> gf;
и gf.store(0, std::memory_order_release);
atomic<long>
без блокировки на любой платформе, которая поддерживает InterlockedExchange
, AFAIK, так что вы должны быть в порядке смешивать и сочетать. (Или просто используйте gf.exchange()
, чтобы взять блокировку. Если вы открываете свои собственные блокировки, имейте в виду, что вы должны зацикливаться на операции только для чтения + _mm_pause()
во время ожидания блокировки, не забивайте xchg
или lock cmpxchg
и, возможно, задержит разблокировку. См. Блокирует манипулирование памятью с помощью встроенной сборки .
Это один из случаев, когда предупреждение в Почему целочисленное присваивание естественной выравниваемой переменной atomic на x86? , что вам нужно atomic<>
, чтобы убедиться, что компилятор действительно хранит где / когда вам нужно это относится.