メインコンテンツ

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

アトミックな読み込みと保存のシーケンスがアトミックではありません

読み込み操作と格納操作の間にアクセス可能な変数

説明

この欠陥は、以下の関数を使用して、アトミック変数を読み込んでから格納した場合に発生します。

  • 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);
}

この例では、atomic_bool 型の変数 flag が関数 toggle_flag() 内で 2 回参照されています。この関数は変数を読み込み、その値を否定して、新しい値を元の変数に格納します。2 つのスレッドで toggle_flag() を呼び出す場合、2 つ目のスレッドは 1 つ目のスレッドの読み込み操作と格納操作の間に flag にアクセスできます。最終的に flag が不適切な状態になる可能性があります。

修正 — 複合代入を使用して変数を変更

1 つの修正方法として、複合代入演算子を使用して 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
影響度: Medium

バージョン履歴

R2018b で導入