パフォーマンスが重要なC++でマルチスレッドアプリケーションを作成しています。スレッド間で小さな構造をコピーするときは、多くのロックを使用する必要があります。このため、スピンロックを使用することを選択しました。
私はこれについていくつかの調査と速度テストを行いましたが、ほとんどの実装はほぼ同じくらい高速であることがわかりました。
- SpinCountが1000に設定されたMicrosoftのCRITICAL_SECTIONは、約140時間単位をスコアリングします
- このアルゴリズムをMicrosoftのInterlockedCompareExchangeスコアで実装すると、約95時間単位になります。
- また、このコード
__asm {}
のようなものを使用してインラインアセンブリを使用しようとしましたが、スコアは約70時間単位ですが、適切なメモリバリアが作成されているかどうかはわかりません。
編集:ここに示されている時間は、2つのスレッドがスピンロックを1,000,000回ロックおよびロック解除するのにかかる時間です。
これは大きな違いではないことは知っていますが、スピンロックは頻繁に使用されるオブジェクトであるため、プログラマーはスピンロックを作成するための可能な限り最速の方法に同意したと思います。しかし、それをグーグルすると、多くの異なるアプローチにつながります。この前述の方法CMPXCHG8B
は、 32ビットレジスタを比較する代わりにインラインアセンブリと命令を使用して実装した場合に最速になると思います。さらに、メモリバリアを考慮に入れる必要があります。これは、コア間の共有メモリに対する「排他的権利」を保証するLOCK CMPXHG8B(私は思いますか?)によって行うことができます。ついに[いくつかの提案]忙しい待ち時間にはNOP:REPを伴うべきだとこれにより、ハイパースレッディングプロセッサが別のスレッドに切り替えることができるようになりますが、これが正しいかどうかはわかりません。
さまざまなスピンロックのパフォーマンステストから、大きな違いはないことがわかりますが、純粋に学術的な目的のために、どれが最も速いかを知りたいと思います。ただし、アセンブリ言語とメモリバリアの経験は非常に限られているため、次のテンプレートでLOCKCMPXCHG8Bと適切なメモリバリアを使用して提供した最後の例のアセンブリコードを誰かが記述できれば幸いです。
__asm
{
spin_lock:
;locking code.
spin_unlock:
;unlocking code.
}