Intel は強力なハードウェア メモリ モデルを提供しているため、C++11 プログラムで「memory_order_relaxed」を使用する利点はありますか? または、違いがないため、デフォルトの「順次一貫性」のままにしておきますか?
2 に答える
コードを正しくするために必要な最小限の保証を常に使用してください。
それ以上でもそれ以下でもありません。
そうすれば、実装に対する不必要な依存関係を回避できるため、移植コストを削減しながら、可能な限り最速のプログラムを取得できます。
もちろん、自分のコードを移植することを決して気にしないと確信している場合は、自分のプラットフォームでは問題にならないことがわかっている場合に、より強力な保証を行うことで、コードが正しいことを証明することがより簡単になる可能性があります。
誤用しにくい、推論しやすい、または短いことも、パフォーマンスの低い構造を使用する理由として完全に受け入れられています。
コンピュータ サイエンスのほとんどの回答と同様に、これに対する回答は「場合による」です。
まず第一に、シーケンシャル コンシステント オーダリングには何のペナルティも発生しないという考えは正しくありません。コード (および場合によってはコンパイラ) によっては、ペナルティが発生する可能性があります。
第 2 に、メモリ順序の制約について賢明な決定を下すには、関係するデータをどのように使用しているかを考える (そして理解する) 必要があります。
memory_order_relaxed は、アトミックである必要があるスタンドアロン カウンターのようなものに役立ちますが、他のものとは直接関係がないため、「他のもの」と一貫性を保つ必要はありません。shared_ptr
典型的な例は、またはの一部の古い実装などの参照カウントですstd::string
。この場合、カウンターがアトミックにインクリメントおよびデクリメントされること、およびカウンターへの変更がすべてのスレッドに表示されることを保証する必要があるだけです。しかし、特に、一貫性を維持する必要がある関連データがないため、他のものとの順序付けについてはあまり気にしません。
シーケンシャル コンシステント オーダリングは、ほぼ正反対です。これはおそらく最も簡単に適用できます。シングル スレッドとほぼ同じようにコードを記述し、実装によって正しく動作することが保証されます (スレッド化をまったく考慮する必要がないと言っているわけではありませんが、順序の一貫性が保たれます)。一般に、それについて考える必要はほとんどありませんが、一般的に最も遅いモデルでもあります)。
取得/解放の整合性は、通常、2 つ以上の関連する情報があり、一方が他方の前後にのみ表示されるようにする必要がある場合に使用されます。私が最近扱った 1 つの例として、大まかにインメモリ データベースのようなものを構築していると仮定しましょう。いくつかのデータがあり、いくつかのメタデータがあります (そして、それぞれを多かれ少なかれ別々に保存しています)。
メタデータは、(とりわけ) データベースの検索に使用されます。誰かが特定のデータを見つけた場合、そのデータが実際にデータベースに存在することを保証したいと考えています。
これを保証するために、データが常にメタデータの前に存在し、少なくともメタデータが存在する限り存在し続けることを保証したいと考えています。誰かがメタデータを使用してデータベースを検索し、使用したいデータが実際には存在しないのに見つけられると、データベースの一貫性が失われます。
したがって、この場合、レコードを追加するときは、最初にデータを追加し、次にメタデータを追加する必要があります。コンパイラは 2 つのデータを並べ替えてはなりません。同様に、レコードを削除する場合は、メタデータを削除して (誰もデータを見つけられないように)、データ自体を削除する必要があります。データ自体の場合、参照カウントを使用して、現在そのデータにアクセスしているクライアントの数を追跡し、誰かが使用しようとしている間に削除しないようにすることができます。
したがって、この場合、メタデータとデータには取得/解放セマンティクスを使用し、参照カウントには緩和された順序付けを使用できます。または、コードをできるだけ単純に保ちたい場合は、少なくともいくらかのペナルティが発生する可能性がありますが (おそらく発生する可能性があります)、全体を通して順次一貫性を使用できます。