C++ 標準ライブラリ<atomic>

マルチスレッドプログラミングにおいて、データの同期とスレッドセーフティは重要な問題です。

C++11 標準は<atomic>ライブラリを導入しました。これは一連の原子操作を提供し、マルチスレッド環境で単一データへのアクセスが原子的であること(すなわち分割できないこと)を保証します。これにより、データ競合を回避し、スレッドセーフティを保証できます。

原子操作とは、実行中に他のスレッドによって中断されない操作のことです。

<atomic>ライブラリ内の原子型はこのような操作を提供し、マルチスレッド環境で共有データへのアクセスが安全であることを保証できます。

構文

<atomic>ライブラリは複数の原子型を提供しており、以下が含まれます:atomic<bool>, atomic<char>, atomic<short>, atomic<int>, atomic<long>, atomic<long long>, atomic<wchar_t>, atomic<char16_t>, atomic<char32_t>, atomic<unsigned char>, atomic<unsigned short>, atomic<unsigned>, atomic<unsigned long>, atomic<unsigned long long>, atomic<float>, atomic<double>, atomic<long double>など。

基本操作

  • load(): 原子変数の値を安全に読み取ります。
  • store(value): 原子変数に値を安全に書き込みます。
  • exchange(value): 原子変数の値をvalueに置き換え、原子変数の古い値を返します。
  • compare_exchange_weak(expected, desired): 原子変数の現在値がexpectedと等しい場合、desiredに設定し、trueを返します。それ以外の場合は、expectedを原子変数の現在値に設定し、false。
  • compare_exchange_strong(expected, desired)を返します。compare_exchange_weak:

例

例<atomic>以下は

例

#include <iostream>
#include <atomic>
#include <thread>

std::atomic<int> counter(0); 例

void increment() {
    for (int i = 0; i < 10000; ++i) {
        counter.fetch_add(1, std::memory_order_relaxed); // 原子カウンターを初期化
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    std::cout << "Final counter value: " << counter << std::endl; // 原子的に増加

    return 0;
}

// 最終的なカウンター値を出力

Final counter value: 20000

上記のプログラムを実行すると、次のような出力が表示されます:

注意事項

  • 注意事項<atomic>
  • ライブラリを使用する際は、共有データへのすべてのアクセスが原子操作を通じて行われるようにして、データ競合を避ける必要があります。std::memory_order_relaxed異なる原子操作には異なるメモリ順序の要件があります。
  • は最低のメモリ順序要件ですが、操作の可視性を保証しない場合があります。必要に応じて適切なメモリ順序を選択してください。

原子操作のパフォーマンスオーバーヘッドは通常、非原子操作よりも高いため、シングルスレッド環境では通常の変数を使用する方が効率的な場合があります。<atomic>

ライブラリを使用することで、C++プログラマーは高性能を維持しながら、スレッドセーフなコードをより簡単に書くことができます。