単純な 2 スレッド通信の例であっても、これを C11 アトミックおよび memory_fence スタイルで表現して適切なメモリ順序を取得するのは困難です。
共有データ:
volatile int flag, bucket;
プロデューサー スレッド:
while (true) {
int value = producer_work();
while (atomic_load_explicit(&flag, memory_order_acquire))
; // busy wait
bucket = value;
atomic_store_explicit(&flag, 1, memory_order_release);
}
消費者スレッド:
while (true) {
while (!atomic_load_explicit(&flag, memory_order_acquire))
; // busy wait
int data = bucket;
atomic_thread_fence(/* memory_order ??? */);
atomic_store_explicit(&flag, 0, memory_order_release);
consumer_work(data);
}
私が理解している限り、上記のコードは、store-in-bucket -> flag-store -> flag-load -> load-from-bucket を適切に順序付けます。ただし、バケットからのロードと新しいデータでのバケットの再書き込みの間に競合状態が残っていると思います。atomic_thread_fence()
バケットの読み取りに続く順序を強制するには、バケットの読み取りと次のatomic_storeの間に明示的なものが必要になると思います。残念ながらmemory_order
、memory_order_seq_cst
.
本当に汚い解決策は、消費者スレッドでダミー値を再割り当てbucket
することです。これは、消費者の読み取り専用の概念と矛盾します。
古い C99/GCC の世界では、__sync_synchronize()
十分に強力であると信じている従来型を使用できました。
このいわゆる反依存性を同期させるための、より優れた C11 スタイルのソリューションは何でしょうか?
(もちろん、そのような低レベルのコーディングを避け、利用可能な高レベルの構造を使用する必要があることは承知していますが、理解したいと思います...)