Скажем есть две функции для обновления и возвращения в среднем некоторого свойства измеряемого:Release Приобретать семантику Compute Среднее
void Class::Update(int delta)
{
m_accumulatedValue += delta;
++ m_count;
}
double Class::GetAverage()
{
return m_accumulatedValue/(double)m_count;
}
Теперь предположим, что они должны быть изменены, чтобы работать в многопоточной среде с резьбой бассейн, в котором любой поток может быть предложено выполнить одно из них - то есть, поток выполнения каждого из них может быть другой один каждый раз, когда:
std::atomic<int> m_accumulatedValue;
std::atomic<int> m_count;
// ...
void Class::Update(int delta)
{
m_accumulatedValue.fetch_add(delta , std::memory_order_relaxed);
m_count.fetch_add(1 , std::memory_order_release);
}
double Class::GetAverage()
{
auto count = m_count.load(std::memory_order_acquire);
auto acc = m_accumulatedValue.load(std::memory_order_relaxed);
return acc/(double)count;
}
Я пытаюсь понять, приобретаемой и освободить память упорядоченности.
Предположим, что одновременных вызовов одного и того же объекта нет для Update()
, но могут быть одновременными вызовами на одном и том же объекте для Update()
и GetAverage()
.
За то, что я прочитал, приобретаемая нагрузка m_count
в GetAverage()
запрещает изменение порядка загрузки m_accumulatedValue
перед ним и в то же время гарантирует, что любые изменения в m_accumulatedValue
исполнение Update()
видно на резьбу призванию GetAverage()
после изменения на m_count
также видно, для магазина, выполненного на m_cout
, Update()
имеет заказ на выпуск.
Это то, что я только что сказал правильно?
GetAverage()
(с указанной гарантией несовместимости звонков на Update()
) всегда верный правильный ответ? Или может быть способ возврата среднего значения с некоторыми значениями, «более обновленными», чем другие?
Нужно ли быть атомарным m_accumulatedValue
?
'memory_order_relaxed' не запрещает другому потоку видеть новое значение, оно просто не требует его.Таким образом, все еще может быть состояние гонки. –
Помимо семантики порядка памяти этот код не работает. Один из возможных вариантов выполнения состоит в том, что один поток добавляет к 'm_accumulatedValue', затем другой поток читает' m_accumulatedValue' ** и ** 'm_count', тогда первый поток обновляет' m_count'. Среднее значение, рассчитанное по второму потоку, будет неправильным. –
Нет. Нет. Может быть. Нет. Почему бы не использовать взаимное исключение? – jotik