Безопасно использовать типы atomic из Си в динамических структурах?

При реализации одной нехитрой структуры данных, которая должна работать в многопоточном приложении, меня сильно насторожило обилие undefined behavior в описании стандарта stdatomic для языка Си. Даже при быстром поиске можно сразу же столкнутся с такими при инициализации переменной:

Calling this function on an atomic object that has already been initialized (either on construction or by calling this function earlier) causes undefined behavior


If obj was not default-constructed, the behavior is undefined.


И тут возникает вопрос. Допустим у нас есть структура, в которой есть atomic переменная. Выделяя память и инициализируя переменную, мы можем в дальнейшем использовать ее не сталкиваясь с undefined behavior. Но что если таких структур у нас много и их расположение в заранее определенной области памяти может меняться при работе?

Например, я хочу сделать стек, где элементы этого стека будут иметь заранее неизвестный размер (заголовок и следующий за ним произвольный массив). Каждый раз добавляя новый элемент (подчеркну, что в заранее выделенной памяти фиксированного размера), мы должны инициализировать атомарную переменную, а при удалении мы с ней ничего делать не должны, ибо соответствующая функция в стандарте отсутствует. В процессе работы и многократного создания/удаления элементов стека, мы каждый раз инициализируем новую атомарную переменную, которая может быть в памяти где угодно, включая те адреса, где раньше лежала старая переменная. Выходит мы можем инициализировать переменную дважды, а тогда, согласно стандарту, получим undefined behavior. Даже если мы исключаем возможность race condition, безопасно ли использовать атомарные переменные таким способом?

Честно говоря, я совершенно не понимаю, как происходит инициализация таких переменных в современных процессорах и компиляторах. Вероятно для некоторых случаев никакой специальной инициализации и вовсе не нужно, а для некоторых она создает блокировки.
  • Вопрос задан
  • 150 просмотров
Решения вопроса 1
@res2001
Developer, ex-admin
Атомарные переменные - это такие же переменные как и остальные. Инициализировать их вы можете сколько угодно раз. Это относится только к встроенным типам. Атомарные классы - это сказка.
Но на них накладываются некоторые ограничения:
1. выравнивание переменной - переменная должна находится по адресу обычно кратному размеру переменной. Если не будет правильного выравнивания, то intelовские процы могут сделать 2 операции чтения, что уже не будет атомарной операцией. Другие процы могут сгенерировать какое-нибудь исключение.
2. атомарная переменная всегда volatile - т.е. компилятор не может ее кэшировать в регистре, всегда идет обращение к памяти.
Не все атомарные переменные в std действительно атомарны. Это проверяется с помощью atomic_is_lock_free(). Атомарность зависит от платформы. Например на x86 int64 - не атомарна из-за ограничений процессора. Тогда как на 32 битных АРМах она вполне атомарна.
При обычном чтении/записи атомарных переменных (с упорядочиванием памяти memory_order_seq_cst) происходит синхронизация кэшей ядер - из-за чего атомарные операции "дороже" не атомарных. Но этот процесс на разных архитектурах стоит по разному. Для синхронизации кэшей есть отдельные ассемблерные инструкции.

В целом все undefined behavior для атомарных переменных в std связаны с:
1. возможностью объявить атомарным любой класс
2. не для всех встроенных типов на конкретной платформе гарантируется реальная атомарность (atomic_is_lock_free).
3. если вы не будете соблюдать ограничения, то же ничего гарантировать нельзя.
Так что особо пугаться undefined behavior не стоит. Просто соблюдайте ограничения, не используйте атомарные классы и удостоверьтесь, что встроенные типы на вашей платформе действительно атомарны.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
Eltex Новосибирск
от 80 000 ₽
Flipper Devices Inc. Москва
от 100 000 ₽
4Taps Mobile Тольятти
от 120 000 до 190 000 ₽
03 мар. 2021, в 11:48
1000 руб./за проект
03 мар. 2021, в 11:26
1000 руб./за проект
03 мар. 2021, в 10:29
4000 руб./за проект