Атомное чтение гарантирует чтение последнего значения? - PullRequest
0 голосов
/ 28 октября 2018

В C ++ у нас есть ключевые слова volatile и atomic class.Разница между ними в том, что volatile не гарантирует поточно-ориентированное параллельное чтение и запись, а лишь гарантирует, что компилятор не будет хранить значение переменной в кэше, а вместо этого загрузит переменную из памяти, в то время как atomic гарантирует поточно-ориентированное параллельное чтение и запись.

Как мы знаем, атомарная операция чтения неделима , т.е. ни один поток не может записать новое значение в переменную, пока один или несколько потоков читают значение переменной, поэтому я думаю, что мы всегда читаем самое последнее значение, но яя не уверен:)

Итак, мой вопрос: если мы объявляем атомарную переменную, всегда ли мы получаем последнее значение переменной, вызывающее load() операция ?

Ответы [ 2 ]

0 голосов
/ 29 октября 2018

если мы объявляем атомарную переменную, всегда ли мы получаем самое последнее значение переменной, вызывающей операцию load ()?

Да, для некоторого определения latest .

Проблема параллелизма заключается в том, что невозможно рассуждать о порядке событий обычным образом.Это происходит из-за фундаментального ограничения в оборудовании, где единственным способом установить глобальный порядок операций на нескольких ядрах будет их сериализация (и устранение всех преимуществ производительности параллельных вычислений в процессе).

Вместо этого современные процессоры предоставляют дополнительный механизм для восстановления порядка между определенными операциями.Атомика - это абстракция на уровне языка для этого механизма.Представьте себе сценарий, в котором два atomic<int> s a и b совместно используются потоками (и давайте далее предположим, что они были инициализированы в 0):

// thread #1
a.store(1);
b.store(1);

// thread #2
while(b.load() == 0) { /* spin */ }
assert(a.load() == 1);

Утверждение здесь гарантированнодержать.Поток # 2 будет наблюдать «последнее» значение a.

. Стандарт не говорит о том, что именно в цикле будет наблюдаться изменение значения b с 0 на 1.,Мы знаем, что это произойдет через некоторое время после записи потоком # 1, и мы также знаем, что это произойдет после записи в a.Но мы не знаем, как долго это будет продолжаться.

Подобные рассуждения еще более усложняются тем фактом, что различным потокам разрешается расходиться во время определенных записей.Если вы переключитесь на более слабый порядок памяти , один поток может наблюдать записи в различные атомарные переменные, происходящие в порядке , отличном от того, что наблюдается в другом потоке.

0 голосов
/ 28 октября 2018

Когда мы говорим о доступе к памяти на современных архитектурах, мы обычно игнорируем «точное местоположение», из которого читается значение.

Операция чтения может извлекать данные из кэша (L0 / L1 / ...), ОЗУ или даже жесткий диск (например, при замене памяти).

Эти ключевые слова сообщают компилятору, какие операции сборки следует использовать при доступе к данным.

volatile

Ключевое слово, которое указывает компилятору всегда читать значение переменной из памяти, а не из регистра.

Эта «память» все еще может быть кешем, но в случаечто этот «адрес» в кеше считается «грязным», что означает, что значение изменилось другим процессором, значение будет перезагружено.

Это гарантирует, что мы никогда не прочитаем устаревшее значение.

Но, если тип объявления volatile не является примитивным, чьи операции чтения / записи являются атомарными (в отношении инструкций по сборке, которые его читают / пишут) по своей природе, мы можем прочитать промежуточное значение (writer удалось записать только половину байтов к моменту, когда читатель прочитает его).

atomic

И компилятор видит операцию load (чтение),в основном он делает то же самое, что и для значения volatile, за исключением использования атомарных операций (это означает, что мы никогда не будем читать промежуточное значение).

Итак, что такоеРазница ???

Разница заключается в операциях записи между процессорами.При работе с энергозависимой переменной, если ЦП 1 устанавливает значение, а ЦП 2 считывает его, считыватель может прочитать старое значение.

Но как это может быть?Ключевое слово volatile обещает, что мы не будем читать устаревшие значения!

Ну, это потому, что писатель не опубликовал значение !И хотя читатель пытается прочитать его, он читает старый.

Когда компилятор наталкивается на операцию store (запись) для атомарной переменной, он:

  • Устанавливаетзначение атомарно в памяти
  • Объявляет, что значение изменилось

После объявления все процессоры будут знать, что они должны перечитать значение переменной, потому что их кэшибыть помечен как «грязный».

Этот механизм очень похож на операции, выполняемые с файлами.Когда ваше приложение записывает в файл на жестком диске, другие приложения могут видеть или не видеть новую информацию, в зависимости от того, сбрасывало ли ваше приложение данные на жесткий диск.

Если данные не былине очищается, то он просто находится где-то в кешах вашего приложения и виден только сам по себе.Как только вы очистите его, каждый, кто откроет файл, увидит новое состояние.

...