что делает с ++ атомарным - PullRequest
1 голос
/ 10 июля 2019

Я просто знаю, что даже код int64_t_variable = 10 не является атомарной операцией.например,

int64_t i = 0;
i = 100;

в другом потоке (скажем, T2) он может прочитать значение, которое не является 0 или 100.

  1. - это правда выше?
  2. std::atomic<int64_t> i; i.store(100, std::memory_order_relaxed) является атомным.Итак, какое волшебство использует атом, чтобы это произошло на основе Q1, верно?
  3. Я всегда думаю, что любая операция, которая обрабатывает менее 64 бит, является атомарной (предположим, 64-битный процессор), похоже, я ошибался.так для v = n, как я могу узнать, атомное оно или нет?например, если v void *, это атомное или нет?

=================================

Обновление: На мой вопрос: когда T2 прочитает i, мне подходят и 0, и 100.но любой другой результат не является разумным.Это главное.так что я не думаю, что кэш или компилятор могут сделать это.

Ответы [ 3 ]

4 голосов
/ 10 июля 2019

выше ли это правда?

Да. Если вы не используете синхронизацию (std::atmoic<>, std::mutex, ...), то любые изменения, сделанные вами в одном потоке, не могут быть обнаружены в других потоках. Может даже быть, что компилятор что-то оптимизирует, потому что нет никакой возможности изменить его функцию. Например

bool flag = true;

void stop_stuff() 
{ 
    flag = false; 
}

void do_stuff()
{
    while (flag)
        std::cout << "never stop";
}

, поскольку для flag нет синхронизации, компилятор может предположить, что он никогда не изменится optmize, даже проверяя флаг в условии цикла. Если это произойдет, то независимо от того, сколько раз вы звоните stop_stuff, do_stuff никогда не закончится.

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

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

std::atomic<int64_t> i; i.store(100, std::memory_order_relaxed) является атомным. так какая магия используется атомами, чтобы это произошло на основе Q1, верно?

Либо использует атомарный примитив, который предоставляет ваша система, либо использует механизм блокировки, например std::mutex, для защиты доступа.

Я всегда думаю, что любая операция, которая обрабатывает менее 64 бит, является атомарной (предположим, 64-битный процессор), похоже, я ошибался. так что для v = n, как я могу узнать, атомное оно или нет? например, если v void *, это атомарно или нет?

Хотя это может быть верно для некоторых систем, это не так для модели памяти C ++. Единственные атомарные вещи - это std::atomic<T>.

1 голос
/ 10 июля 2019
  1. Да.Причины включают в себя «для этого требуется несколько инструкций», «кеширование памяти может привести к путанице» и «компилятор может делать удивительные вещи (иначе UB), если вы не упомянули, что переменная может быть изменена в другом месте».

  2. Все вышеперечисленные причины необходимо устранить, и std::atomic предоставляет информацию для реализации библиотеки компилятора / C ++.Компилятору не будет позволено проводить неожиданные оптимизации, он может при необходимости производить сброс кеша, а реализация может использовать механизм блокировки, чтобы предотвратить чередование различных операций над одним и тем же объектом.Обратите внимание, что не все из них могут быть необходимы: в x86 встроены некоторые гарантии атомарности. Вы можете узнать, является ли данный тип std::atomic всегда свободным от блокировки на вашей платформе с помощью std::atomic::is_always_lockfree иданный экземпляр без блокировки (например, из-за доступа с выравниванием / без выравнивания).

  3. Если вы не используете std::atomic, у вас нет гарантий атомарностипо вышеуказанным причинам.Он может быть атомарным на уровне команд вашего процессора, но C ++ определяется на абстрактной машине без таких гарантий.Если ваш код полагается на атомарность на абстрактной машине, но не может указать это, компилятор может выполнить недопустимые оптимизации и произвести UB.

0 голосов
/ 10 июля 2019
  1. Да, например, если имеется 8-битная память, другой поток может прочитать частично записанную переменную.
  2. Все, что требуется для гарантии правильных результатов, может быть ничем, встроенными атомарными операциями, блокировками и т. Д..
  3. void * не является атомарным std :: atomic является.То же самое для символа, чтобы быть атомарным, его нужно явно указать как атомарный.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...