これは実際には正しくありませんが、同時実行性には次の 2 つの形式があると考えると便利です。
- ロックフリー同時実行
- ロックベースの同時実行
ソフトウェア ロック ベースの同時実行性は、スタック上のどこか (多くの場合、カーネル) でロック フリーのアトミック命令を使用して実装されるため、これは正しくありません。ただし、ロック フリーのアトミック命令はすべて、最終的にメモリ バスでハードウェア ロックを取得することになります。したがって、実際には、ロックフリーの同時実行とロックベースの同時実行は同じです。
しかし、概念的には、ユーザー アプリケーションのレベルでは、これらは 2 つの異なる方法です。
ロック ベースの同時実行は、コードの重要なセクションへのアクセスを "ロック" するという考えに基づいています。1 つのスレッドがクリティカル セクションを "ロック" すると、他のスレッドは同じクリティカル セクション内でコードを実行できなくなります。これは通常、「ミューテックス」を使用して行われます。このミューテックスは、OS スケジューラと連携し、ロックされたクリティカル セクションに入るのを待機している間、スレッドを実行不能にします。もう 1 つのアプローチは、クリティカル セクションが使用可能になるまで、スレッドをループ内でスピンさせ、何の役にも立たない「スピン ロック」を使用することです。
ロックフリー同時実行は、ハードウェアによってアトミックに実行されることが保証されているアトミック命令 (特に CPU によってサポートされている) を使用するという考えに基づいています。Interlocked.Increment は、ロックフリー同時実行の良い例です。アトミックインクリメントを行う特別な CPU 命令を呼び出すだけです。
ロックフリーの同時実行は困難です。クリティカル セクションの長さと複雑さが増すにつれて、特に難しくなります。クリティカル セクションの任意のステップは、一度に任意の数のスレッドで同時に実行でき、非常に異なる速度で移動できます。それにもかかわらず、システム全体の結果が正しいままであることを確認する必要があります。インクリメントのようなものは単純です (cs は 1 つの命令にすぎません)。より複雑なクリティカル セクションでは、物事が非常に複雑になる可能性があります。
ロックベースの同時実行も困難ですが、ロックフリーの同時実行ほど困難ではありません。コードの任意の複雑な領域を作成し、いつでも 1 つのスレッドだけがそれを実行していることを知ることができます。
ただし、ロックフリーの同時実行には 1 つの大きな利点があります。速度です。正しく使用すると、ロックベースの同時実行よりも桁違いに高速になる可能性があります。スピン ループは、何もせずに CPU リソースを浪費するため、長時間実行されるクリティカル セクションには適していません。ミューテックスは、多くのオーバーヘッドが発生するため、小さなクリティカル セクションには適していません。最低でもモードの切り替えが必要で、最悪の場合は複数のコンテキストの切り替えが必要です。
マネージド ヒープの実装を検討してください。「new」が呼び出されるたびにOSを呼び出すのは恐ろしいことです。アプリのパフォーマンスを損なう可能性があります。ただし、ロックフリーの同時実行を使用すると、インターロックされたインクリメントを使用してジェネレーション 0 のメモリ割り当てを実装することができます (CLR がそれを行うかどうかはわかりませんが、そうでない場合は驚くでしょう。それは巨大になる可能性があります)。節約。
永続的なスタックや avl ツリーなど、ロックのないデータ構造など、他の用途もあります。彼らは通常「cas」(比較と交換)を使用します。
ただし、ロックベースの同時実行とロックフリーの同時実行が実際に同等である理由は、それぞれの実装の詳細によるものです。
スピンロックは通常、ループ条件でアトミック命令 (通常は cas) を使用します。ミューテックスは、実装時にスピン ロックまたは内部カーネル構造のアトミック更新のいずれかを使用する必要があります。
アトミック命令は、ハードウェア ロックを使用して実装されます。
いずれにせよ、どちらにも一連のトレードオフがあり、通常はパフォーマンスと複雑さが中心です。ミューテックスは、ロック フリー コードよりも速くも遅くもなります。ロック フリー コードは、mutex よりも複雑な場合もあれば、複雑でない場合もあります。使用する適切なメカニズムは、特定の状況によって異なります。
さて、あなたの質問に答えるために:
未満の場合にインターロック比較交換を行ったメソッドは、ロックを使用していないことを呼び出し元に暗示します。インクリメントや比較交換と同じように、単一の命令で実装することはできません。ループ内でインターロックされた比較交換を使用して、(より少ない計算をするために) 減算を実行してシミュレートできます。ミューテックスを使用して行うこともできます (ただし、これはロックを意味するため、名前に「インターロック」を使用すると誤解を招く可能性があります)。「シミュレートされたインターロック経由のcas」バージョンを構築するのは適切ですか? 場合によります。コードが非常に頻繁に呼び出され、スレッドの競合がほとんどない場合、答えはイエスです。そうでない場合は、適度に高い定数係数を使用した O(1) 操作を無限 (または非常に長い) ループに変えることができます。この場合、ミューテックスを使用することをお勧めします。
ほとんどの場合、それだけの価値はありません。