Расслабленный заказ памяти при fetch_add

Я просматриваю книгу Мары «Атомика и блокировки», в которой показан пример кода, в котором предполагается, что функции a и b выполняются одновременно:

static X: AtomicI32 = AtomicI32::new(0);

fn a() {
    X.fetch_add(5, Relaxed);
    X.fetch_add(10, Relaxed);
}

fn b() {
    let a = X.load(Relaxed);
    let b = X.load(Relaxed);
    let c = X.load(Relaxed);
    let d = X.load(Relaxed);
    println!("{a} {b} {c} {d}");
}

Ссылка: https://marabos.nl/atomics/memory-ordering.html#relaxed

В нем говорится, что, поскольку модифицирует только один поток X, возможен только один возможный порядок модификации X: 0 -> 5 -> 15.

Мой вопрос: почему это не может быть так: 0 -> 10 -> 15 из-за возможности переупорядочения инструкций? Я спрашиваю об этом, потому что ранее в этой главе было указано:

Логика проверки того, что определенное изменение порядка или другая оптимизация не повлияет на поведение вашей программы, не учитывает другие потоки.

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

Изменение порядка операторов, при котором можно наблюдать эффект этих операторов, не допускается ни для ЦП, ни для компилятора.

cafce25 23.08.2024 17:42

@cafce25: В целом это неправда. Два расслабленных атомарных хранилища в разных местах могут стать видимыми для других потоков в порядке, отличном от порядка программы. Ключевым фактором здесь является то, что обе операции выполняются над одним и тем же объектом, а объект является атомарным.

Peter Cordes 24.08.2024 04:30

@PeterCordes Это не то, что я сказал, я сказал, что эти утверждения не могут быть переопределены, это отличается от того, что их эффект становится видимым в другом потоке. Хотя, согласитесь, это менее актуально.

cafce25 24.08.2024 07:46

@cafce25: Вы сказали, что изменение порядка запрещено в любом случае, когда разница заметна. Это неверно для неатомарных или не-seq_cst порядков памяти для разных объектов, когда наблюдателем является другой поток. Или вы использовали слово «тех» для того, чтобы ограничить его особым случаем в вопросе? Если вы это имели в виду, ваш смысл не совсем понятен.

Peter Cordes 24.08.2024 12:01
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
1
4
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Есть переупорядочение и есть переупорядочение :)

Атомарные инструкции для отдельных атомарных значений всегда упорядочены, независимо от используемого порядка памяти.

Упорядочение памяти влияет только на порядок операций с памятью над другими значениями (атомарными или нет) относительно атомарной операции.

В формализме C++, используемом в стандарте, порядок модификации переменной совместим с порядком последовательности для модификаций, поступающих из одного и того же потока. Я предполагаю, что Rust работает таким же образом, если его формализм отдаленно похож на C++.

Peter Cordes 23.08.2024 19:46

@PeterCordes Да, Rust работает так же, как C++. Можете ли вы разместить здесь соответствующую ссылку на формализм C++? Мне не удалось найти это в той же теме.

Sibi 24.08.2024 04:58

@Sibi: согласованность записи и записи (eel.is/c++draft/intro.races#15 ) ссылки происходят до порядка модификации одного объекта. И eel.is/c++draft/intro.races#10 — один из способов, чтобы A произошло раньше B, — это упорядочить его раньше. В терминах C++ «последовательность перед» — это «порядок выполнения программы в одном потоке».

Peter Cordes 24.08.2024 05:23

Другие вопросы по теме