Работают ли атомарные операции в разных процессах так же, как они работают в разных потоках?

StackOverflow https://stackoverflow.com/questions/1585544

Вопрос

Очевидно, что атомарные операции гарантируют, что разные потоки не будут искажать значение.Но верно ли это по-прежнему для всех процессов при использовании общей памяти?Даже если процессы запланированы операционной системой для запуска на разных ядрах?Или на разных процессорах?

Редактировать:Кроме того, если это небезопасно, то разве это небезопасно даже в такой операционной системе, как Linux, где процессы и потоки одинаковы с точки зрения планировщика?

Это было полезно?

Решение

tl; dr: Прочтите мелкий шрифт в документации по атомарным операциям.Некоторые из них будут атомарными по своей конструкции, но могут спотыкаться о определенные типы переменных.В общем, однако, атомарная операция будет поддерживать свой контракт между различными процессами точно так же, как это происходит между потоками.

Атомарная операция действительно гарантирует только то, что у вас не будет несогласованного состояния, если вы вызываетесь двумя объектами одновременно.Например, атомарное приращение, вызываемое двумя разными потоками или процессами для одного и того же целого числа, всегда будет вести себя следующим образом:

  1. x = начальное значение (нулевое для целей этого обсуждения)
  2. Объект A увеличивает x и возвращает результат самому себе:результат = x = 1.
  3. Объект B увеличивает x и возвращает результат самому себе:результат = x = 2.

где A и B указывают на первый и второй поток или процесс, который выполняет вызов.

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

  1. x = начальное значение снова = нулю.
  2. Объект A вызывает x = x + 1.Чтобы вычислить x + 1, A проверяет значение x (ноль) и добавляет 1.
  3. Объект B вызывает x = x + 1.Чтобы вычислить x + 1, B проверяет значение x (по-прежнему равное нулю) и добавляет 1.
  4. Объект B (по счастливой случайности) финиширует первым и присваивает x результат x + 1 = 1 (шаг 3).x теперь равен 1.
  5. Объект A финиширует вторым и присваивает x результат x + 1 = 1 (шаг 2).x теперь равен 1.

Обратите внимание на условие гонки, поскольку объект B проходит мимо A и первым завершает выражение.

Теперь представьте, если бы x был 64-разрядным double, у которого не гарантировано наличие атомарных назначений.В этом случае вы могли бы легко увидеть что-то вроде этого:

  1. 64-битный double x = 0.
  2. Объект A пытается присвоить 0x1122334455667788 x.Первые 32 бита присваиваются первыми, оставляя x равным 0x1122334400000000.
  3. Объект B запускается и присваивает 0xffeeddccbbaa9988 x .Случайно обе 32-разрядные половины обновлены, и x теперь равен = 0xffeeddccbbaa9988.
  4. Объект A завершает свое назначение второй половиной, и x теперь равен = 0xffeeddcc55667788.

Эти неатомные назначения являются одними из самых отвратительных параллельных ошибок, которые вам когда-либо приходилось диагностировать.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top