Приведет ли ослабленный порядок памяти к бесконечному циклу? - PullRequest
0 голосов
/ 22 мая 2018

Код, о котором идет речь:

#include <atomic>
#include <thread>

std::atomic_bool stop(false);

void wait_on_stop() {
  while (!stop.load(std::memory_order_relaxed));
}

int main() {
  std::thread t(wait_on_stop);
  stop.store(true, std::memory_order_relaxed);
  t.join();
}

Поскольку здесь используется std::memory_order_relaxed, я предполагаю, что компилятор может изменить порядок stop.store() после t.join().В результате t.join() никогда не вернется.Правильно ли это рассуждение?

Если да, решит ли проблема изменение stop.store(true, std::memory_order_relaxed) на stop.store(true)?

Ответы [ 2 ]

0 голосов
/ 22 мая 2018

Любая функция, определение которой недоступно в текущей единице перевода, считается функцией ввода-вывода.Предполагается, что такие вызовы вызывают побочные эффекты, и компилятор не может перемещать следующие операторы, предшествующие вызову, или предшествующие операторы, чтобы следовать за вызовом.

[intro.execution] :

Чтение объекта, обозначенного изменчивым значением glvalue ([basic.lval]), изменение объекта, вызов функции ввода-вывода библиотеки или вызов функции, выполняющей любую из этих операций, являются побочными эффектами, которые являются изменениями.в состоянии исполнительной среды.Оценка выражения (или подвыражения) в целом включает в себя как вычисления значений (включая определение идентичности объекта для оценки glvalue и выборку значения, ранее назначенного объекту для оценки prvalue), так и инициирование побочных эффектов.Когда возвращается вызов функции ввода-вывода библиотеки или оценивается доступ через энергозависимое значение glvalue, побочный эффект считается завершенным, даже если некоторые внешние действия, подразумеваемые вызовом (например, сам ввод-вывод) или изменяемым доступомвозможно, еще не завершено.

И

Каждое вычисление значения и побочный эффект, связанный с полным выражением, секвенируются перед каждым вычислением значения и побочным эффектом, связанным со следующимполное выражение для оценки.

Здесь std::thread конструктор и std::thread::join являются такими функциями (они в конечном итоге вызывают специфичные для платформы функции потоков, недоступные в текущем TU) с побочными эффектами.stop.store также вызывает побочные эффекты (хранение памяти является побочным эффектом).Следовательно, stop.store нельзя перемещать до конструктора std::thread или после вызовов std::thread::join.

0 голосов
/ 22 мая 2018

[intro.progress] / 18:

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

[atomics.order] / 12:

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

Это необязательная рекомендация.Если ваша реализация следует за ними - как должны делать высококачественные реализации - у вас все в порядке.В противном случае вы облажались.В обоих случаях независимо от используемого порядка памяти.


В абстрактной машине C ++ отсутствует понятие «переупорядочение».В абстрактной семантике основной поток сохраняется в атомарном состоянии, а затем блокируется, и поэтому, если реализация делает хранилище видимым для нагрузок в течение конечного промежутка времени, тогда другой поток загрузит это сохраненное значение в течение конечного промежутка времени ипрекратить.И наоборот, если реализация по какой-либо причине не делает этого, тогда ваш другой поток будет зацикливаться вечно.Используемый порядок памяти не имеет значения.

Я никогда не считал целесообразным рассуждение о «переупорядочении».Он смешивает детали реализации низкого уровня с моделью памяти высокого уровня и делает вещи более запутанными, а не меньшими.

...