CompareAndExchange на трех атомарных переменных

Я хочу сравнить и обменять 3 атомные переменные:

std::atomic<int> a;
std::atomic<int> expected;
std::atomic<int> new;

int expectedValue = std::atomic_load_explicit(&expected, std::memory_order_relaxed);
int newValue = std::atomic_load_explicit(&new, std::memory_order_relaxed);

std::atomic_compare_exchange_strong_explicit(
    &a, 
    &expectedValue, 
    newValue, 
    std::memory_order_relaxed, 
    std::memory_order_relaxed);

Но если между чтением expected а также new переменные и сравнивая их с a, один другой поток изменяет свои значения, текущий поток будет работать с предыдущими значениями, поэтому я изменяю код на него:

while(true)
{
    int expectedValue = std::atomic_load_explicit(&expected, std::memory_order_relaxed);
    int newValue = std::atomic_load_explicit(&new, std::memory_order_relaxed);

    std::atomic_compare_exchange_strong_explicit(
        &a, 
        &expectedValue, 
        newValue, 
        std::memory_order_relaxed, 
        std::memory_order_relaxed);

    int newExpectedValue = std::atomic_load_explicit(&expected, std::memory_order_relaxed);
    int newNewValue = std::atomic_load_explicit(&new, std::memory_order_relaxed);

    if(newExpectedValue == expectedValue && newNewValue == newValue)
        break;
}

Мой код правильный? или есть лучший способ сделать это?

2 ответа

Ваша переписанная функция все еще может давать противоречивые результаты. Что, если expected меняется после загрузки в newExpectedValue, но прежде чем проверять, newExpectedValue == expectedValue? Что, если new а также expected изменить после загрузки expected, но прежде new?

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

Почему expected а также new Атомная на первом месте? Как правило, вы вычисляете новое значение каким-то образом в каком-то потоке, и только этот поток знает новое значение и выполняет compare_exchange. Точно так же значение expected это старое значение до того, как этот поток начал свои вычисления, но это ожидаемое, старое значение снова важно только для этого одного потока.

Короче: expected а также new не должны быть разделены между потоками.

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