Atomic load and store sequence not atomic

Переменная, доступная между операциями загрузки и хранения

Описание

Этот дефект возникает, когда вы используете эти функции для загрузки, а затем храните атомарную переменную.

  • Функции C:

    • atomic_load()

    • atomic_load_explicit()

    • atomic_store()

    • atomic_store_explicit()

  • Функции C++:

    • std::atomic_load()

    • std::atomic_load_explicit()

    • std::atomic_store()

    • std::atomic_store_explicit()

    • std::atomic::load()

    • std::atomic::store()

Поток не может прервать атомарную загрузку или операцию атомарного хранилища переменной, но поток может прервать хранилище, а затем загрузить последовательность.

Риск

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

Зафиксировать

Чтобы считать, изменять и хранить переменную атомарно, используйте составной оператор назначения, такой как +=, atomic_compare_exchange() или atomic_fetch_*-семейные функции.

Примеры

расширить все


#include <stdatomic.h>
#include <stdbool.h>

static atomic_bool flag = ATOMIC_VAR_INIT(false);

void init_flag(void)
{
    atomic_init(&flag, false);
}

void toggle_flag(void)
{
    bool temp_flag = atomic_load(&flag);
    temp_flag = !temp_flag;
    atomic_store(&flag, temp_flag);
}

bool get_flag(void)
{
    return atomic_load(&flag);
}

В этом примере переменные flag типа atomic_bool ссылка дважды внутри toggle_flag() функция. Функция загружает переменную, отменяет ее значение, затем сохраняет новое значение назад к переменной. Если вызываются два потока toggle_flag()второй поток может получить доступ к flag между операциями загрузки и хранения первого потока. flag может оказаться в неправильном состоянии.

Коррекция - Используйте составное назначение для изменения переменной

Одной из возможных коррекций является использование оператора составного назначения для переключения значения flag. Стандарт C определяет операцию при помощи ^= как атомарный.


#include <stdatomic.h>
#include <stdbool.h>

static atomic_bool flag = ATOMIC_VAR_INIT(false);

void toggle_flag(void)
{
    flag ^= 1;
}

bool get_flag(void)
{
    return flag;
}

Информация о результатах

Группа: Параллелизм
Язык: C | C++
По умолчанию: On для рукописного кода, off для сгенерированного кода
Синтаксис командной строки : ATOMIC_VAR_SEQUENCE_NOT_ATOMIC
Влияние: Средний
Введенный в R2018b