Атомарное поведение унарных операторов приращения

Где-то я читал, что унарные операторы атомарны по своей природе и поэтому их можно использовать в многопоточной среде. Чтобы подтвердить то же самое, я написал две отдельные программы, в которых

  1. Я использовал переменную x и увеличивал ее с помощью унарного оператора ++ x
  2. Я использовал переменную x и увеличил ее, используя x = x + 1

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

То, что ++x атомарен, не означает, что x=x+1 нет? (С логической точки зрения я сомневаюсь, что ++x и так всегда атомарен)

Ctx 18.12.2018 12:31

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

Simon F 18.12.2018 12:32

Неважно, является ли какая-то инструкция атомарной, у вас либо правильная синхронизация, либо гонка.

Baum mit Augen 18.12.2018 12:32

Я подозреваю, что где бы вы ни читали, слово «атомарный» использовалось в другом смысле, чем в контексте параллелизма. Либо так, либо они были совершенно неправы, и не стоит доверять всему, что вы там видели.

molbdnilo 18.12.2018 12:38
std::atomic может быть реализован кем-то, кто знает оборудование, на которое вы нацеливаетесь, возможно, намного лучше, чем вы. Пусть за работу сделает эксперт. Используйте std::atomic, когда вам нужна атомарность.
Pete Becker 18.12.2018 15:20

В C ++ до / после исправления не являются унарные операторы, например & * + - ~ !. но часть унарное выражение. Таким образом, заголовок вопроса не соответствует тексту.

chux - Reinstate Monica 18.12.2018 16:20

@chux В вопросе написано «унарный оператор», а не «унарный оператор» с дефисом и курсивом, что подразумевает специфическое для грамматики C / C++ значение. Postfix operator++ также не является частью унарное выражение, но постфиксное выражение. Унарный оператор - это общий, широко понимаемый термин, который здесь правильно используется.

palotasb 18.12.2018 17:03

@palotasb постфиксное выражение - это одна из форм унарное выражение. Верно, я использую указанное в C значение, поскольку это объективно. по сравнению с более широко понимаемым термином, который может иметь различные толкования. В конце концов, OP ищет конкретный ответ для C / C++, а не для общего программирования.

chux - Reinstate Monica 18.12.2018 18:47
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
9
8
428
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

Ответ принят как подходящий

Somewhere I read that unary operators are atomic by nature and so they can be used as it is in multi threaded environment.

Этот источник совершенно неверен. Вам нужно использовать std::atomic (или эквивалент C) для достижения атомарности - унарные операции не являются чем-то особенным.


I compared the disassembly of both programs and found no difference

Это не означает, что сгенерированные операции атомарны. Нет никакой разницы, поскольку любой достойный компилятор оптимизирует x=x+1 и ++x в одну и ту же сборку (при условии встроенных типов).

Сравнение сборки может подтвердить обратное. Если вы знаете, что сборка i = i + 1 неатомарна, то эта же сборка неатомарна для i++, следовательно, последняя не является атомарной.

palotasb 18.12.2018 17:05

Утверждение, что унарный оператор обязательно атомарен, является мифом.

Например, для ++x требуется чтение и запись в x, что открывает возможность гонки данных.

Тот факт, что ++x компилируется с тем же кодом, что и x = x + 1, не имеет значения.

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

Somewhere I read that unary operators are atomic by nature and so they can be used as it is in multi threaded environment.

Это неправда. x++, например, требует загрузки x, добавления и сохранения x. Эти инструкции не атомарны по своей природе.

Не правда. Даже если бы это было так, какая тогда причина была бы в https://en.cppreference.com/w/cpp/atomic/atomic#Type_aliases?

Я думаю, что они, вероятно, имели в виду, что вычисление такой операции обычно очень незначительное и, следовательно, с высокой вероятностью никогда не будет состояния гонки, что в основном верно для живого кода, где вы не вычисляете x ++ в 4 циклах одновременно.

Атомарность операции stronglr зависит от целевой системы. Унарная операция может не быть атомарной в системах RMW, таких как микроконтроллеры RISC.

На этот вопрос нет единого универсального ответа.

Хороший ответ (хотя и немного краткий), поскольку он не утверждает, что он никогда не может быть атомарным (как это делают другие). Но: есть «единственный общий ответ» на вопрос: «Нет, унарные операторы нет являются атомарными по природе».

Ctx 18.12.2018 12:45

@Ctx это зависит от уровня абстракции. Если абстрагироваться от реализации и железа - да. Если нет - нет.

0___________ 18.12.2018 13:02

@P__J__ Язык C определен в терминах абстрактной машины: «Семантические описания в этом международном стандарте описывают поведение абстрактной машины, в которой вопросы оптимизации не имеют значения». Единственный общий ответ является «унарные операторы не атомарны».

Andrew Henle 18.12.2018 14:22

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

0___________ 18.12.2018 14:31

При написании кросс-платформенного C++ у вас есть только атомарное поведение при использовании std::atomic<>.

Это правда, что на некоторых платформах, таких как Intel 64bit, процессор гарантирует, что inc является атомарным. Однако, пожалуйста, не пишите код, который зависит от этого! Как ваш будущий отладчик, я хотел бы знать, какие данные предназначены для совместного использования по потокам, а какие нет.

Использование std::atomic<int> может потребовать немного больше работы для написания, однако оно гарантирует, что все будет вести себя атомарно (на каждой платформе) либо путем возврата к требованиям платформы (std :: atomic :: is_lock_free), либо путем явной блокировки доступа. Он также вставляет ограждения, чтобы убедиться, что кеши других ядер процессора недействительны (если этого требует платформа).

На практике для Intel 64bit это должно дать вам ту же сборку, если нет, зарегистрировать ошибку в вашем компиляторе.

В то же время некоторые операции с целыми числами могут не быть атомарными (оператор * =), std::atomic просто не хранит эти операции, требуя от вас правильной работы с ними.

Кстати, ++x и x = x+1 - это разные операции, они могут быть оптимизированы для одной и той же сборки. Учитывая неатомарные требования к платформе, вторая внезапно представляет собой ошибку, на решение которой уходит несколько дней.

Вы делаете предположение о сгенерированном коде, если сгенерирована только одна инструкция, да, она будет атомарной, иначе нет.

В вашем случае это предполагает, что целевой процессор имеет инструкцию inc <address>, и компилятор сгенерирует ее.

Вы не указали тип x.

  1. Если x - 32-битное целое число, когда платформа - 16- или 8-битная, операция 'x ++' обязательно сделаю несколько операций
  2. x может быть даже не базовым типом, x может быть экземпляром класса, где оператор ++ делает гораздо более сложные вещи, чем просто увеличивает целое число

«операция определенно будет выполнять несколько операций» - я бы не стал делать это утверждение. У вас могут быть 32-битные регистры на 16-битных архитектурах, и вам нужна только блокировка шины, за которой следует приращение, чтобы x ++ был атомарным.

Bathsheba 18.12.2018 14:06

Я согласен с вами, что это будет зависеть от обрабатываемого объекта. Для упрощения я использовал целое число 32 бита. Но мне следовало использовать 64-битное целое число, так как моя машина 64-битная, поэтому ОС (Windows 10)

user3505805 18.12.2018 15:19

Atomic behavior of unary operators

В C ++ до / после исправления не являются унарные операторы, например & * + - ~ !. но часть унарное выражение. Таким образом, заголовок вопроса не соответствует тексту.

Даже унарный оператор, такой как +, не является атомарным, поскольку доступ к объекту (например, long long) заставляет выполнять несколько операций чтения кода операции.

Другие вопросы по теме