【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
を活用することで、安全かつ効率的な並行処理が可能になります。