にしても、単純な2スレッドの通信たとえば、私は適切なメモリ順序を得るために、C11原子とmemory_fenceスタイルでこれを表現する難しさを持っている:C11メモリフェンスの使用量
共有データ:
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);
}
消費者THRE広告: - >旗-店 - >旗ロード - >負荷からバケット
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);
}
私の知る限り理解し、上記のコードは、適切ストア・イン・バケットを注文します。しかし、私はバケットからのロードの間に競合状態が残っていて、バケットを新しいデータで再度書き直すと思う。バケット読み込みに続く命令を強制するには、バケット読み込みと次のatomic_storeの間に明示的にatomic_thread_fence()
が必要であると思います。残念ながら、memory_order_seq_cst
さえも、先行するロードで何かを強制するために、memory_order
引数がないようです。
本当に汚い解決策は、民生用スレッドのbucket
をダミー値で再割り当てすることです。これは、コンシューマの読み取り専用の概念と矛盾します。
古いC99/GCCの世界では、十分に強力であると私が信じている伝統的な__sync_synchronize()
を使うことができました。
このいわゆるアンチ依存性を同期させる、より良いC11スタイルのソリューションは何でしょうか?
(もちろん、私は私が良く、このような低レベルのコーディングを避けるため、利用可能な高レベルの構文を使用する必要があることを承知していますが、私は理解したいと思います...)
私はC++プログラマではありませんが、(概念的に) 'atomic_thread_fence()'呼び出しが必要であるかどうかはわかりません。フラグ更新は、リリースセマンティクスを有し、先行するストア命令がその全体にわたって再順序付けされるのを防止する(例えば、ストアを「データ」に)。 'data'へのストアは、' bucket'からの読み込みに依存しているので、読み込みがフラグ解放を過ぎても再順序付けできません。完全なフェンスが必要な場合、私はなぜそれを聞くのが大好きです。 –
答えではないので、ちょうどコメント:C11の 'atomic_flag'データ型を再現したようです。これは正確にこの意味を実装していますが、最終的にはハードウェアでより直接的な実装をしています。 'atomic_flag'は、ロックフリーであることが保証されている唯一のアトミックデータ型です。したがって、より複雑な操作よりも常に優先されることになります。また、一貫性を確保するために特別なフェンスは必要ありません。 –
Mike S、あなたの返信は私には魅力的だと思われますが...私はメモリフェンスがメモリサブシステム上のものを保証していて、ld/st opsに影響を与えていると思いました。上記の例では、 'data'はおそらくレジスタ変数になるため、その代入はストア演算を作成しません。それはメモリ同期のバケットからの負荷だけを残しますか? (それ以降のC11メモリの順序はありません) –