Какие C++11 <atomic> операции / заказы памяти гарантируют свежесть?

Возможный дубликат:
Параллельность: атомарная и энергозависимая в модели памяти C++11

С С ++ 11 <atomic> спецификация, есть ли гарантия свежести? Описания различных порядков памяти имеют дело только с переупорядочениями (насколько я видел).

В частности, в этой ситуации:

#include <atomic>

std::atomic<int> cancel_work(0);

// Thread 1 is executing this function
void thread1_func() {

    ...

    while (cancel_work.load(<some memory order>) == 0) {
        ...do work...
    }
}


// Thread 2 executes this function
void thread2_func() {

    ...

    cancel_work.store(1, <some memory order>);

    ...

}

Если поток 1 и поток 2 не делятся никакими другими данными, кроме cancel_workмне кажется, что никаких гарантий заказа не нужны и std::memory_order_relax достаточно как для магазина, так и для загрузки. Но гарантирует ли это, что поток 1 когда-нибудь увидит обновление cancel_work вместо того, чтобы просто многократно читать строку локального кэша, не обновляя его из основной памяти? Если нет, то какой минимум необходим, чтобы сделать эту гарантию?

3 ответа

Решение

Ничто не гарантирует этого: все связано с заказом. Четное memory_order_seq_cst просто гарантирует, что все происходит в одном общем порядке. Теоретически, компилятор / библиотека / процессор может планировать каждую загрузку из cancel_store в конце программы.

В 29.3p13 есть общее утверждение, что

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

Но нет никакой спецификации на то, что составляет "разумное количество времени".

Так: memory_order_relaxed должно быть просто отлично, но memory_order_seq_cst может работать лучше на некоторых платформах, так как строка кэша может быть перезагружена раньше.

Похоже, этот ответ также отвечает на мой вопрос. Что ж, надеюсь, мой вопрос поможет гуглерам лучше его найти.

Тема 1 "ДОЛЖНА" увидеть обновленную cancel_work в "разумное количество времени", однако, что именно является разумным, (очевидно) не указано.

Вызов функции [которая не указана компилятором] автоматически перезагрузит все регистры, которые содержат переменные, которые не являются непосредственно локальными. Таким образом, пока процессор, выполняющий thread1_func(), очищает или обновляет содержимое кэша в зависимости от store, это будет работать.

memory_order_relax должен гарантировать, что данные (в какой-то момент в будущем) будут сброшены из любых других кэшей процессоров [это происходит автоматически в x86, но не для всех типов процессоров, например, для некоторых процессоров ARM требуется "очистка на основе кода"], но это не гарантируется, что это произойдет ДО любых других операций записи [в обычные или атомарные переменные].

И обратите внимание, что порядок памяти влияет ТОЛЬКО на текущий поток / процессор. То, что другой поток или процессор делает во время хранения или загрузки, полностью зависит от этого потока / процессора. Я имею в виду, что thread1_func() в вашем случае может быть в состоянии прочитать значение 0 в течение небольшого промежутка времени после значения 1 был написан другим процессором / потоком. Все атомарные операции гарантируются тем, что ЛИБО получает значение СТАРЫЙ или НОВОЕ, никогда между ними [если вы не используете memory_order_relax, который не обеспечивает какой-либо порядок загрузки / сохранения между операциями в потоке. Однако, какой бы порядок памяти вы ни использовали, atomic должна гарантировать [при условии правильной реализации], что значение в конечном итоге обновляется. Просто сложнее сказать, когда в расслабленном случае.

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