Pull to refresh

Comments 12

Все-таки, в первом листинге нужно объявить a как volatile

что это даст?

В таком случае компилятор не будет иметь права оптимизировать доступы к этой переменной, насколько мне известно. Если попробовать скомпилировать с флагом -O3, то вы (не гарантированно, конечно) получите просто ноль из-за оптимизаций.

Атомики дают такие же гарантии, даже больше.

Это старый подход, когда volatile использовался для предотвращения оптимизаций компилятором. Но это было валидно, до того как memory model была формализована для С и С++.

Уточню, volatile необходимо использовать когда значение может измениться из вне, например, при работе с портами.

Наверное выглядело бы как нагромождение, т.к. код немного вырван из контекста и не понятно зачем там volatile. Конечно, если человек интересуется тем, как работают атомики, наверное должен знать, как работает volatile, но тут, буд-то несёт больше лишнюю нагрузку нежели нужный для осмысления примера

Спасибо за статью!

Я бы рекомендовал использовать weak для спинлоков (CAS в цикле) и strong в остальных случаях, но, строго говоря, никто не мешает вам делать иначе.

На моей памяти зависит от архитектуры, для x86-64 weak/strong cas операции работают одинаково, в то же время для arm ризличны (больше к слову).

Про модель памяти (memory_ordering и отношения: happens before и прочие) как-то бегло по сравнению с разбором на уровне памяти/кешей, хотя там рассказывать много можно)

До середины где-то прочитал и всё время какое-то раздражение от несовпадения того что в коде написано и что потом говорится.

В одном потоке инкремент, в другом декремент, а в описании дважды инкремент)

В разделе с описанием compare_exchange_strong тоже не попадание в результате ожидаемого вывода результата.

Непонятное ощущение. Закрыл, чтобы не взрывало мозг. Хотя как "разрывать нужно нейронные связи" - сработала отлично

В целом информативный текст. Поправить и отличный(до половины ибо дальше не читал)

Было бы неплохо добавить иллюстрации ассемблерного кода для memory orderring , какие инструкции сообщают процессору не менять последовательность, на разных архитектурах.

Чего же вы бросили в конце, не дописали?

std::atomic<T> в стандарте разрешён только для trivially copyable типов.

«Сложный» класс (c виртуалами, нестандартным деструктором, std::string внутри и т.п.) туда напрямую класть нельзя.

Для сложного состояния используется паттерн: атомарный указатель/shared_ptr на объект, а не сам объект в atomic.

Да, атомарный shared_ptr - это, наверное, теретически лучший паттерн для реализации атомарного сложного состояния, но в современных компиляторах (я проврял clang 21.1.0 gcc 15.2 ) он не lock free, к сожалению (по крайней мере для x86-64). Поэтому смысла в нем пока немного. Правда, если количество взаимодействющих нитей ограничено, возможны его сравнительно несложные самодельные lock-free паллиативы (с заранее заготовленным небольшим пулом объектов).

Sign up to leave a comment.

Articles