Hacker News Digest

Тег: #atomic-operations

Постов: 3

From Rust to reality: The hidden journey of fetch_max (questdb.com)

В Rust есть встроенная атомарная операция fetch_max, которая отсутствует в Java и C++. Она позволяет безопасно обновлять максимальное значение в многопоточной среде без явного написания цикла CAS. Исследование показало, что fetch_max генерируется макросом atomic_int! в стандартной библиотеке Rust, который создаёт методы для атомарных типов.

На уровне компиляции LLVM эта операция превращается в цикл сравнения и обмена, скрытый от программиста. Это демонстрирует, как Rust абстрагирует сложные низкоуровневые детали, предоставляя удобные и безопасные примитивы для конкурентного программирования.

by bluestreak • 23 сентября 2025 г. в 21:24 • 234 points

ОригиналHN

#rust#java#c++#llvm#atomic-operations#cas#concurrency#memory-model

Комментарии (49)

  • Автор обнаружил, что Rust имеет встроенную атомарную операцию fetch_max, которой нет в Java и C++ (хотя она планируется в C++26).
  • Обсуждение затронуло технические детали реализации атомарных операций (например, на ARM и x86), их производительность при высоком уровне конкуренции и возможность компилятором оптимизировать циклы CAS в нативные инструкции.
  • Участники отметили, что подобные низкоуровневые операции существуют и в других средах, таких как GPU (HLSL/GLSL/CUDA) и RISC-V.
  • Многие выразили признательность автору за познавательную статью, углубившую их понимание модели памяти и атомарных операций.
  • Несколько человек поинтересовались, был ли нанят кандидат, упомянутый в исходной статье, на что автор ответил, что тот не подошел по культуре.

Wild performance tricks (davidlattimore.github.io)

В Wild-линковщике для Rust применяют несколько продвинутых техник оптимизации параллельной работы. Например, используют split_off_mut для безопасного разделения мутабельных срезов Vec<SymbolId> между потоками, что позволяет обрабатывать символы каждого объекта параллельно без блокировок, сохраняя кэш-локальность.

Для инициализации вектора без задержек на основном потоке задействуют крейт sharded-vec-writer: предварительно аллоцируют память, разбивают её на сегменты по числу символов в объектах и заполняют их параллельно через VecWriter, что ускоряет стартовую фазу.

В случаях, когда требуются случайные записи в общий вектор (например, для обработки дубликатов символов в C++), переходят на атомарные операции. Вместо стабильного, но ограниченного AtomicU32::from_mut_slice (только nightly) или постоянного использования атомиков (что снижает производительность), временно преобразуют &[SymbolId] в &[AtomicSymbolId] через unsafe-конверсию, экономя на издержках синхронизации в основном коде.

by tbillington • 23 сентября 2025 г. в 08:16 • 105 points

ОригиналHN

#rust#parallelism#performance-optimization#memory-management#concurrency#vector#atomic-operations#rayon

Комментарии (67)

  • Обсуждаются оптимизации Rust, такие как преобразование Vec в IntoIter и обратно для эффективного повторного использования аллокации, что реализовано в стандартной библиотеке как специальный случай.
  • Высказываются предостережения против некоторых "трюков производительности", например, перемещения аллокации в другой поток для освобождения, из-за особенностей работы аллокаторов и сомнительной выгоды.
  • Поднимается вопрос о надёжности оптимизаций компилятора (LLVM) в релизных сборках, которые могут меняться между версиями и сложны для верификации, что контрастирует с медленными debug-сборками.
  • Отмечается, что многие трюки направлены на обход ограничений borrow checker для получения разрешения на выполнение операций, а не на решение аппаратных задач производительности.
  • Обсуждается преимущество Rust в безопасном параллелизме (например, с Rayon) по сравнению с C/C++, где обеспечение потоковой безопасности значительно сложнее.

C++: Strongly Happens Before? (nekrozqliphort.github.io)

Коротко о «strongly happens-before»

В C++20 появилось новое отношение strongly happens-before (SHB), потому что старое happens-before оказалось недостаточно строгим.

Пример кода

std::atomic<int> x{0}, y{0};

// thread-1
x.store(1, seq_cst);
y.store(1, release);

// thread-2
int b = y.fetch_add(1, seq_cst); // b = 1
int c = y.load(relaxed);         // c = 3

// thread-3
y.store(3, seq_cst);
int a = x.load(seq_cst);         // a = 0

Почему нужен SHB

  • Каждый атомарный объект имеет modification order — полный порядок всех записей.
  • Классические правила coherence (write-write, read-read, read-write, write-read) связывают happens-before с этим порядком.
  • Но при смешанных memory_order (например, release + seq_cst) между потоками могут образоваться «дыры», где старое happens-before не гарантирует ожидаемую последовательность.

Отличие SHB от HB

  • SHB добавляет требование: если операция A strongly happens-before B, то все наблюдатели видят записи A раньше записей B, даже при разных memory_order.
  • Для seq_cst SHB совпадает с HB; для release/acquire HB может быть, а SHB — нет.

Итог

Если пользуетесь только seq_cst, можно не заморачиваться. При смешанных порядках SHB — формальный способ не получить «невозможные» значения.

by signa11 • 28 августа 2025 г. в 14:54 • 86 points

ОригиналHN

#c++#multithreading#memory-model#atomic-operations#c++20

Комментарии (14)

  • Участники обсуждают различие между «strong happens-before» в Java и более слабой моделью C++.
  • Код из статьи считается не «простым», а академическим примером; порядок запуска потоков ОС не гарантирует.
  • Наблюдаемые в комментариях значения могут показаться странными, но они допустимы при отсутствии дополнительной синхронизации.
  • Смысл слабых моделей памяти — формально описать множество всех допустимых исполнений, учитывая кэши, оптимизации компилятора и т. д.
  • Добавление ещё одного атомика для «упорядочивания» может, наоборот, запретить именно тот «неинтуитивный» порядок, который автор статьи исследует.