Барьер памяти (англ. memory barrier, membar, memory fence, fence instruction) — вид барьерной инструкции, которая приказывает компилятору (при генерации инструкций) и центральному процессору (при исполнении инструкций) устанавливать строгую последовательность между обращениями к памяти до и после барьера. Это означает, что все обращения к памяти перед барьером будут гарантированно выполнены до первого обращения к памяти после барьера.
Барьеры памяти необходимы, так как большинство современных процессоров используют оптимизации производительности, которые могут привести к переупорядочиванию инструкций. Также переупорядочивание обращений к памяти может быть вызвано компилятором в процессе оптимизации использования регистров целевого процессора. Такие перестановки обычно не влияют на корректность программы с одним потоком исполнения, но могут вызвать непредсказуемое поведение в многопоточных программах. Правила изменения порядка исполнения инструкций зависят от архитектуры. Некоторые архитектуры предоставляют несколько типов барьеров с различными гарантиями. Например, amd64 предоставляет следующие инструкции: SFENCE
(англ. store fence), LFENCE
(англ. load fence), MFENCE
(англ. memory fence)[1].
Intel Itanium обеспечивает отдельные «запоминающие» (англ. acquire) и «освобождающие» (англ. release) барьеры памяти, которые учитывают видимость операций чтения после записи с точки зрения читателя и писателя соответственно.
Барьеры памяти, как правило, используются при реализации примитивов синхронизации, неблокирующих структур данных и драйверов, которые взаимодействуют с аппаратным обеспечением.
Следующая программа исполняется на двух процессорах.
Изначально ячейки памяти x
и f
содержат значение 0
. Программа в процессоре #1 находится в цикле пока f
равен нулю, затем она печатает значение x
. Программа в процессоре #2 записывает значение 42
в x
, а затем сохраняет значение 1
в f
. Псевдокод для двух программных фрагментов:
Процессор #1:
while (f == 0) { }
// Здесь необходим барьер
print x;
Процессор #2:
x = 42;
// Здесь необходим барьер
f = 1;
Хотя ожидается, что print
всегда напечатает «42», но если процессор #2 изменит порядок исполнения инструкций и вначале изменит значение f
то print может вывести «0». Аналогично, процессор #1 может прочитать x
перед f
, и print снова выведет неожидаемое значение. Для большинства программ, ни одна из этих ситуаций не приемлема. Барьер памяти для процессора #2 может быть вставлен перед изменением значения f
. Также можно вставить барьер для процессора #1 перед чтением x
[2].
Барьеры памяти работают только на аппаратном уровне. Компиляторы могут также переупорядочить инструкции как часть оптимизации программы. Меры по предотвращению переупорядочивания необходимы только для данных, которые не защищены примитивами синхронизации.
В языках С и С++, ключевое слово volatile предназначено для исключения оптимизаций компилятора. Используется чаще всего для работы с отображаемым в память вводом-выводом. Однако данное ключевое слово (в отличие от Java) никак не обеспечивает атомарность и защиту от внеочередного исполнения.[3]
Данная страница на сайте WikiSort.ru содержит текст со страницы сайта "Википедия".
Если Вы хотите её отредактировать, то можете сделать это на странице редактирования в Википедии.
Если сделанные Вами правки не будут кем-нибудь удалены, то через несколько дней они появятся на сайте WikiSort.ru .