В большинстве случаев для освобождения ресурса просто сброс блокировки на нуль (как и у вас) почти полностью (например, на процессоре Intel Core), но вам также нужно убедиться, что компилятор не будет обмениваться инструкциями (см. ниже, см. также сообщение gv). Если вы хотите быть строгим (и портативные), есть две вещи, которые необходимо учитывать:
Что компилятор делает: Он может обмениваться инструкции по оптимизации кода, и, таким образом, ввести некоторые тонкие ошибки, если это не «осознавая» многопоточный характер кода. Чтобы этого избежать, можно вставить барьер компилятора.
Что делает процессор: Некоторые процессоры (такие как Intel Itanium, используемые на профессиональных серверах или процессоры ARM, используемые в смартфонах) имеют так называемую «модель ослабленной памяти». На практике это означает, что процессор может принять решение об изменении порядка операций. Опять же, этого можно избежать, используя специальные инструкции (барьер нагрузки и барьер хранения). Например, в процессоре ARM, то DMB инструкция гарантирует, что все операции магазина завершены до следующей инструкции (и она должна быть вставлена в функции, которая освобождает замок)
Вывод: Это очень сложно сделайте код правильным, если у вас есть поддержка некоторых компиляторов/ОС для этих функций (например, stdatomics.h
или std::atomic
в C++ 0x), гораздо лучше полагаться на них, чем написание собственных (но иногда у вас нет выбора) , В конкретном случае стандартного процессора Intel Core я считаю, что то, что вы делаете, является правильным, если вы вставляете компилятор-барьер в операцию выпуска (см. Сообщение g-v).
На время компиляции по сравнению с упорядочением памяти времени выполнения, см: https://en.wikipedia.org/wiki/Memory_ordering
Мой код для некоторых атомных/спин-блокировок, реализованных на различных архитектурах: http://alice.loria.fr/software/geogram/doc/html/atomics_8h.html (но я не уверен, что это 100% правильно)
Связанные вопросы: http://stackoverflow.com/questions/1383363/is-my-spin-lock-implementation-correct-and-optimal http://stackoverflow.com/questions/6810733/do-spin-locks-always -require-a-memory-барьер-это-spinning-on-a-memory-барьер-e http://stackoverflow.com/questions/26307071/does-the-c-volatile-keyword-introduce-a-memory- забор – gavv
Можете ли вы пожалуйста, дополните? Почему именно здесь мне нужен барьер памяти? Что пошло не так, и как, если я его не использую? –
'' 'Lock()' '' требует «получить барьер», чтобы гарантировать, что все изменения, сделанные при блокировке блокировки, будут применяться только после обновления '' 'pFlag'''. '' 'Unlock()' '' требует «барьера выпуска», чтобы гарантировать, что все изменения, сделанные при блокировке спин-блокировки, будут применены до обновления '' 'pFlag'''. См. Подробности здесь: https://jfdube.wordpress.com/2012/03/08/understanding-memory-ordering/.Это общий подход, но на x86 вам понадобятся только барьеры компилятора вместо барьеров для приобретения и выпуска; см. здесь: http://preshing.com/20120913/acquire-and-release-semantics/ – gavv