Почему std :: memory_order_relaxed является предпочтительным в цикле CAS при сбое? - PullRequest
4 голосов
/ 31 октября 2019

Когда дело доходит до реализации CAS Loop с использованием std::atomic, cppreference в этой ссылке дает следующий пример для push:

template<typename T>
class stack
{
    std::atomic<node<T>*> head;
 public:
    void push(const T& data)
    {
      node<T>* new_node = new node<T>(data);
      new_node->next = head.load(std::memory_order_relaxed);

      while(!head.compare_exchange_weak(new_node->next, new_node,
                                        std::memory_order_release,
                                        std::memory_order_relaxed /* Eh? */));
    }
};

сейчас, Я не понимаю, почему std::memory_order_relaxed используется для случая сбоя, потому что, насколько я понимаю, compare_exchange_weak (то же самое для -strong , но я просто буду использовать слабую версию для удобства) является операцией загрузки при сбое, что означает, что она загружается из успешной операции CAS в другом потоке с std::memory_order_release, и, следовательно, она должна использовать std::memory_order_acquire, чтобы быть синхронизированной с вместо ...?

while(!head.compare_exchange_weak(new_node->next, new_node,
                                  std::memory_order_release,
                                  std::memory_order_acquire /* There you go! */));

Что если, гипотетически, «расслабленная нагрузка» получит одно из старых значений, в результате чего снова и снова будет происходить сбой, оставаясь в цикле в течение дополнительного времени?

Следующая ошибкаНа картинке застрял мой мозг.

enter image description here

Разве магазин T2 не должен быть виден в T1? (синхронизировав связь друг с другом)

Итак, чтобы подвести итог моего вопроса,

  • Почему бы не std::memory_order_acquire вместо std::memory_order_relaxed при сбое?
  • Что делает std::memory_order_relaxed достаточным?
  • Означает ли std::memory_order_relaxed при сбое (потенциально) больше циклов?
  • Аналогично, std::memory_order_acquireпри сбое означает (потенциально) меньше циклов? (кроме недостатков производительности)

1 Ответ

0 голосов
/ 01 ноября 2019

Я не понимаю, почему std :: memory_order_relaxed используется для сбоя

И я не понимаю, как вы жалуетесь на отсутствие семантики получения в этой ветке сбояне жалуйтесь на

head.load(std::memory_order_relaxed);

, а затем на

while(!head.compare_exchange_weak(new_node->next, new_node,
                                  std::memory_order_release

, ни у одной из которых нет операции захвата "для синхронизации" с другой операцией, которую выне показывай намЧто это за другая операция, которая вас волнует?

Если эта операция важна, покажите эту операцию и скажите, используйте, как этот код зависит от "публикации" (или сигнала "Я закончил") этой другой операции. .

Ответ: функция push никоим образом не зависит от публикации какого-либо сигнала "Я закончил" другой функцией , поскольку push не использует другие опубликованные данные,не читать другие отправленные элементы и т. д.

Почему бы не std :: memory_order_acquire вместо std :: memory_order_relaxed при сбое?

Для чего получить? Другими словами, чтобы наблюдать, какое достижение?

Значит ли std :: memory_order_relaxed при неудаче (потенциально) больше циклов?

Нет. Режим сбоя не имеет ничего общего с видимостью памяти;это функция механизма кэша ЦП.

РЕДАКТИРОВАТЬ:

Я только что видел текст на вашем изображении:

Не должен магазин из T2быть видимым в T1? (имея синхронизированную связь друг с другом)

На самом деле вы неправильно поняли синхронизированный с: он не распространяет значение считываемой атомарной переменной, поскольку атомарный по определению являетсяПримитив пригоден для использования с расой. Чтение атомарного всегда возвращает значение атомарной переменной , как написано некоторым другим потоком (или тем же самым потоком). Если бы это было не так, то никакая атомарная операция не имела бы смысла.

Нет необходимости упорядочивать память для чтения одной атомарной переменной.

...