sync.Once でのアトミック メモリの順序付け
sync.Once のソース コードを探索しているときに、Atomic を使用する背後にある理由に遭遇しました。 o.done = 1 のような標準的な割り当ての代わりに StoreUint32 を使用します。
Go でのメモリの順序付け
同時プログラミングの基本的な概念はメモリの順序付けであり、これにより共有メモリが確実に共有されます。アクセスはすべてのプロセッサにわたって一貫して観察されます。ただし、アーキテクチャが異なるとメモリの順序付けの実装方法が異なるため、プログラマにとって課題が生じます。
Go は、統一されたメモリ モデルを提供し、緩和的だが一貫したメモリ順序付けを強制することでこの問題に対処します。すべてのメモリ アクセスは非同期であると想定され、原子性や順序性の保証はありません。
同期したアトミック操作は 1 回あります。
緩和されたメモリ モデルにもかかわらず、Go は共有メモリアクセスにアトミック操作を使用して、サポートされているすべてのアーキテクチャにわたって正確性を保証します。 sync.Once では、atomic.StoreUint32 を使用して Done フラグを安全に更新し、フラグが 1 に設定される前に他のゴルーチンが f() の効果を確実に観察できるようにします。
高速パスの最適化
atomic.StoreUint32 は、安全性を維持しながらパフォーマンスを最適化するために、sync.Once の高速パスで利用されます。書き込みと同時にフラグを読み取るとデータ競合が発生するため、完了フラグは最初に atomic.LoadUint32 でチェックされ、次に atomic.StoreUint32 で書き込まれます。
ミューテックス保護
doSlow で使用される mutex は、done フラグを同時書き込みから保護するために機能します。フラグは読み取り操作であるため、ミューテックスなしでも読み取ることができますが、データの破損を防ぐために同時書き込みを同期する必要があります。
要約すると、sync.Once での atomic.StoreUint32 の使用は次の結果です。 Go の緩和されたメモリ モデルと、サポートされているすべてのアーキテクチャでスレッド セーフを保証する必要性。アトミック操作を採用することで、sync.Once は高速パスでのパフォーマンスを最適化しながら、共有メモリへの同時アクセスを安全に調整できます。
以上がsync.Once が標準の割り当てではなく atomic.StoreUint32 を使用するのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。