Comments 11
Различных вариантов комбинации memory_order 6x6 = 36, а рассмотрено почему-то всего 3. Непонятно, зачем было делать это ордеры параметрами методов, когда они, похоже, к типу должны быть привязаны?
Спасибо за замечание. Вы правы, что существует 36 возможных комбинаций. Однако в статье я сознательно сосредоточился на трёх наиболее практичных сценариях для введения в тему. Валидных и полезных комбинаций значительно меньше, так как многие нарушают семантику операций (например, acquire на store). Для полного справочника действительно нужен отдельный материал. Согласен, что вопрос о привязке к типам — интересный дизайн-вопрос, но текущий API предоставляет гибкость, которая часто необходима.
Похоже люди минусуют, но не обьясняют причины, оставлю вам конструктивные улучшения:
1. У вас микс из понятий, статья читается тяжело, многое упущено из обьяснения (можно было оставить ссылки на полезные материалы для ознакомления)
2.Запутывающее определение для Memory Ordering, Memory Ordering не является барьером. Само понятие барьера обозначает совершенно другое, существует два вида барьеров.
На уровне CPU - барьеры MFENCE, LFENCE, SFENCE, открываете AMD64 Architecture Programmer's Manual Volume 3: General Purpose and System Programming Instructions (PUB) (24594), находите mfence на 237 странице, lfence на 231 странице, sfence на 338 странице. В ARM архитектуре это инструкции dmb, dsb, isb
https://developer.arm.com/documentation/dui0802/b/A32-and-T32-Instructions/DMB--DSB--and-ISB?lang=en
На уровне компиляции барьеры нужны для предотвращения оптимизаций компилятора по доступу к памяти, например _ReadWriteBarrier у MSVC или asm volatile("": : :"memory") в GCC и Clang. Пример кода который вы можете исследовать и понять, что такое барьер на уровне компиляции прилагаю ниже.
// Компилируем с O3, смотрим в сгенерированный ассемблерный код.
#include <cstdint>
#include <cstdio>
uint8_t a[256] = {};
__attribute__((noinline)) void f() {
for (int i = 0; i < 256; ++i) {
asm volatile("" ::: "memory"); // <---
a[i]++;
}
}
int main() {
f();
uint8_t sum = 0;
for (int i = 0; i < 256; ++i)
sum += a[i];
printf("sum = %d\n", sum);
}3. Следующее вводит читателя в заблуждение: "Когда использовать seq_cst: когда нужна максимальная простота рассуждения о коде, либо для отладки. Это самый медленный режим."
Правильнее: "каждый поток видит все атомарные операции с seq_cst в одном и том же порядке".
Если вы используете seq_cst для "отладки" это скорее значит, что ваш код запутан и вы сами не можете понять как он работает, либо фундаментально не понимаете для чего нужен Memory Ordering.
4. Вот это утверждение на мой взгляд неверное: "Memory ordering позволяет точно контролировать синхронизацию и производительность"
Правильнее было бы: "Ограничивает видимость операций и переупорядочивание между потоками, что в свою очередь влияет на производительность."
Согласен со всеми четырьмя пунктами: 1. Структура и переходы можно улучшить. 2. Memory ordering ≠ барьер — это критическое различие, спасибо за примеры ARM/AMD. 3. seq_cst не инструмент отладки — это фундаментальная гарантия. 4. "Ограничивает" — правильный глагол, не "контролирует".
Минусуют потому, что тут нейронка чувствуется что в статье, что в комментах автора.
Спасибо за комментарий. Также хотелось бы получить более конструктивную критику именно в контексте раскрываемой в статье темы, полезность, вторичность, плюсы, минусы, какие существенные моменты не учтены или искажены, чтобы на основании данных замечаний сделать статью более информативной и полезной для тех людей, которым данная тема интересна. Возможно, стоит дополнительно создать статью об этических нормах при написании как статей, так и комментариев.
Вы правы, хочешь я напишу еще одну статью с учетом конструктивной критики и сделаю ее более человечной?
Отличная идея, также иногда нужно прогонять и комментарии через нейросеть, чтобы в одном предложении не встречалось и Вы, и ты. Безграмотная речь при написании комментариев несколько снижает доверие как к комментатору, так и к комментарию. Вам статья была полезной?
Объясните, как и кому эта статья может быть полезной? Если я ничего не знаю про атомики, lock free и memory order, то статья не сможет мне это доступно объяснить - вы просто рассыпали горстью все термины, быстро прошлись по ним очень общими фразами, ничего фундаментально не объяснили и были таковы.
Memory order - моя самая тяжелая, вымученная тема, я прочитал по ней столько статей, столько умственных сил приложил, чтобы адекватно понять смысл и причинность этой темы: зачем memory order вообще оказался необходим; роль компилятора, процессора и кеша в этом всем; интуиция, best practices; что реально значат все эти happens-before, syncronizes-with, специфика на разном железе...
И вот приходите вы: вот есть memory order, тут короче lock free, все дела, тут у нас happens before, а еще cas, aba, профилируем значит, а memory_order_seq_cst используем для простоты рассуждения о коде.
После прочтения статьи возникает только один вопрос: что это было? Потом идешь в комментарии, а там: "вам статья была полезной?".
Ещё одна нейро-статья((
Тема не раскрыта, куча терминов и разбросанных понятий, все минусы на статью кидают именно потому, что весь текст статьи чистая нейронка и, заходя сюда, ожидаешь увидеть что-то свежее и интересное, но получаешь информационную кашу.
Многопоточность в современном C++: Lock-Free программирование, Memory Ordering и Atomics