упорядочение памяти в примере повышения безблокировочного кольцевого буфера

Когда я читаю атомарную рассылку о примере реализации кольцевого буфера без ожидания:

https://www.boost.org/doc/libs/1_66_0/doc/html/atomic/usage_examples.html#boost_atomic.usage_examples.example_ringbuffer

Мне интересно, если memory_order_acquire необходимо в

if (next_head == tail_.load(boost::memory_order_acquire))

Кажется, что memory_order_relaxed должен работать так же. Мой аргумент в том, что

 value = ring_[tail];

случается, перед тем

tail_.store(next(tail), boost::memory_order_release)

в вызове pop (). поэтому мы уверены, что данные были прочитаны перед сохранением в вызове push () как

 ring_[head] = value;

Я вставил весь приведенный ниже пример кода для удобства.
Спасибо!

#include <boost/atomic.hpp>

template<typename T, size_t Size>
class ringbuffer {
public:
ringbuffer() : head_(0), tail_(0) {}

bool push(const T & value)
{
size_t head = head_.load(boost::memory_order_relaxed);
size_t next_head = next(head);
if (next_head == tail_.load(boost::memory_order_acquire))

// Может ли tail_.load выше использовать boost :: memory_order_relaxed?

    return false;
ring_[head] = value;
head_.store(next_head, boost::memory_order_release);
return true;
}
bool pop(T & value)
{
size_t tail = tail_.load(boost::memory_order_relaxed);
if (tail == head_.load(boost::memory_order_acquire))
return false;
value = ring_[tail];
tail_.store(next(tail), boost::memory_order_release);
return true;
}
private:
size_t next(size_t current)
{
return (current + 1) % Size;
}
T ring_[Size];
boost::atomic<size_t> head_, tail_;

};

1

Решение

Одна причина в том, что по порядку:

if(next_head == tail_.load(boost::memory_order_acquire))
return false;
ring_[head] = value; // A non-atomic store.

memory_order_acquire гарантирует, что следующее неатомарное хранилище не будет переупорядочено, чтобы предшествовать этой загрузке tail_,

memory_order_relaxedс другой стороны, не препятствует переупорядочению, и, следовательно, не является достаточным здесь.

(Предполагается, что boost::memory_order эквивалентно std::memory_order.)


Release-Acquire заказ:

В строго упорядоченных системах — x86, SPARC TSO, мэйнфрейме IBM и т. Д. — упорядочение по типу выпуска-приобретения является автоматическим для большинства операций. Никаких дополнительных инструкций ЦП для этого режима синхронизации не выдается; затрагиваются только некоторые оптимизации компилятора (например, компилятору запрещается перемещать неатомарные хранилища после выпуска атомарного хранилища или выполнять неатомарные загрузки раньше, чем получение атомарной нагрузки). В слабо упорядоченных системах (ARM, Itanium, PowerPC) используются специальные инструкции по загрузке процессора или ограничению памяти.

1

Другие решения

Насколько я вижу, оба tail_.load(boost::memory_order_acquire) в push() а также head_.load(boost::memory_order_acquire) в pop() можно расслабить и заменить xx.load(boost::memory_order_relaxed),

0

По вопросам рекламы [email protected]