【C言語】stdatomic.hを使って出来ることと典型的な使い方【標準ライブラリ】

【C言語】stdatomic.hを使って出来ることと典型的な使い方【標準ライブラリ】

stdatomic.hとは

stdatomic.h は、C11で導入された標準ライブラリで、マルチスレッド環境でのアトミック操作を提供します。 これにより、スレッド間でデータ競合を防ぎつつ、同期処理を効率的に行うことができます。

アトミック変数の定義と初期化

stdatomic.h を利用することで、アトミックなデータ型を定義できます。

#include <stdatomic.h>
#include <stdio.h>

int main() {
    atomic_int counter = 0;
    printf("初期値: %d\n", counter);
    return 0;
}

基本的なアトミック操作

アトミックな変数に対する基本的な操作として、次のようなものがあります。

アトミックな代入と取得

atomic_int x = 10;
atomic_store(&x, 20); // x に 20 をアトミックに代入
int value = atomic_load(&x); // x の値をアトミックに取得

アトミック加算・減算

atomic_fetch_add(&x, 1); // x += 1
atomic_fetch_sub(&x, 1); // x -= 1

アトミック交換

int old = atomic_exchange(&x, 5); // x の値を 5 に変更し、元の値を取得

比較して交換

int expected = 10;
atomic_compare_exchange_strong(&x, &expected, 20); // x が expected (10) なら 20 に変更

メモリオーダーの種類と使い方

stdatomic.h では、メモリオーダーを指定できます。これにより、スレッド間の可視性と順序を制御できます。

代表的なメモリオーダー

  • memory_order_relaxed – 最適化されるが順序保証なし
  • memory_order_acquire – 読み込みの順序を保証
  • memory_order_release – 書き込みの順序を保証
  • memory_order_seq_cst – 最も強い順序保証

メモリオーダーの使用例

atomic_int x = 0;
atomic_store_explicit(&x, 10, memory_order_release);
int y = atomic_load_explicit(&x, memory_order_acquire);

atomic_flagを用いたフラグ操作

atomic_flag は、最も単純なアトミック変数で、スピンロックなどに使われます。

atomic_flag の使用例

atomic_flag lock = ATOMIC_FLAG_INIT;

void lock_function() {
    while (atomic_flag_test_and_set(&lock)) {
        // 他のスレッドがロックを持っている間はループ
    }
}

void unlock_function() {
    atomic_flag_clear(&lock);
}

stdatomic.hの活用例

カウンタのインクリメント

#include <stdatomic.h>
#include <stdio.h>
#include <pthread.h>

atomic_int counter = 0;

void* thread_func(void* arg) {
    for (int i = 0; i < 100000; i++) {
        atomic_fetch_add(&counter, 1);
    }
    return NULL;
}

int main() {
    pthread_t t1, t2;
    pthread_create(&t1, NULL, thread_func, NULL);
    pthread_create(&t2, NULL, thread_func, NULL);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    printf("Final counter: %d\n", counter);
    return 0;
}

スピンロックの実装

#include <stdatomic.h>
#include <stdio.h>
#include <pthread.h>

atomic_flag lock = ATOMIC_FLAG_INIT;

void lock_function() {
    while (atomic_flag_test_and_set(&lock)) {
        // 忙しい待機
    }
}

void unlock_function() {
    atomic_flag_clear(&lock);
}

void* critical_section(void* arg) {
    lock_function();
    printf("スレッド %ld がクリティカルセクションを実行中\n", (long)arg);
    unlock_function();
    return NULL;
}

int main() {
    pthread_t t1, t2;
    pthread_create(&t1, NULL, critical_section, (void*)1);
    pthread_create(&t2, NULL, critical_section, (void*)2);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    return 0;
}

まとめ

  • stdatomic.h は、マルチスレッド環境での安全なデータ操作を提供
  • 基本的なアトミック操作(代入、取得、加算、交換)をサポート
  • メモリオーダーを適切に使うことで性能と正確性を両立
  • atomic_flag を使ったスピンロックの実装も可能

マルチスレッドプログラミングにおいて、適切にstdatomic.h を活用することで、安全かつ効率的な並行処理が可能になります。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です