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++
Значение по умолчанию: на
Синтаксис командной строки: ATOMIC_VAR_SEQUENCE_NOT_ATOMIC
Удар: носитель

Введенный в R2018b