Получение и освобождение являются барьерами памяти. Если ваша программа считывает данные после барьера получения, вы уверены, что вы будете считывать данные в соответствии с любым предыдущим выпуском любым другим потоком в отношении той же переменной atomi c. Переменные Atomi c гарантированно будут иметь абсолютный порядок (при использовании memory_order_acquire
и memory_order_release
, хотя предусмотрены более слабые операции) для их чтения и записи во всех потоках. Эти барьеры в действительности распространяют этот порядок на любые потоки, использующие эту переменную atomi c. Вы можете использовать атомику, чтобы указать, что что-то «закончено» или «готово», но если потребитель читает за пределами этой переменной atomi c, потребитель не может полагаться на «просмотр» правильных «версий» другой памяти, и атомы будут имеют ограниченное значение.
Заявления о «переходе до» или «продвижении после» являются указанием оптимизатору, что он не должен переупорядочивать операции, чтобы они выполнялись не по порядку. Оптимизаторы очень хороши в переупорядочении инструкций и даже в исключении избыточных операций чтения / записи, но если они реорганизуют код через барьеры памяти, они могут невольно нарушить этот порядок.
Ваш код использует объект std::string
(a) созданный в producer()
до присвоения ptr
и (b) созданная версия этой строки (т. е. версия памяти, которую она занимает) является той, которую читает consumer()
. Проще говоря, consumer()
будет с нетерпением читать строку, как только увидит назначенное значение ptr
, так что, черт возьми, лучше увидеть действительный и полностью построенный объект, или наступят плохие времена. В этом коде «действие» присваивания ptr
- это то, как producer()
«сообщает» consumer
, что строка «готова». Барьер памяти существует, чтобы убедиться, что именно это видит потребитель.
И наоборот, если ptr
был объявлен как обычный std::string *
, компилятор мог бы решить оптимизировать p
и назначить выделенный адрес непосредственно ptr
, и только затем создать объект и назначить int
данные. Вероятно, это катастрофа для потока consumer
, который использует это назначение в качестве индикатора того, что объекты, которые готовит producer
, готовы. Чтобы быть точным, если бы ptr
был указателем, consumer
может никогда не увидеть назначенное значение или на некоторых архитектурах прочитать частично назначенное значение, где были назначены только некоторые байты, и это указывает на расположение мусорной памяти. Однако эти аспекты связаны с тем, что атомы c не являются более широкими барьерами памяти.