マイクロソフトはInterlockedCompareExchange
アトミックな比較とスワップ操作を実行する関数。また、_InterlockedCompareExchange
本質的な。
x86 では、これらはlock cmpxchg
命令を使用して実装されます。
しかし、これら 3 つのアプローチに関するドキュメントを読んでみると、アライメント要件については合意されていないようです。
インテルの参考マニュアル配置については何も言及していない(それ以外はもしアライメントチェックが有効になっていて、アライメントされていないメモリ参照が行われると、例外が生成されます)
私はまた、接頭辞を調べましたlock
。具体的には、
LOCKプレフィックスの整合性はないメモリ フィールドの配置によって影響を受けます。
(強調は筆者による)
つまり、Intel は、アライメントは無関係であると言っているようです。操作はどのような場合でもアトミックになります。
内部_InterlockedCompareExchange
ドキュメントにもアライメントについては何も書かれていないが、InterlockedCompareExchange
関数と述べています
この関数のパラメータは 32 ビット境界に揃える必要があります。そうしないと、この関数はマルチプロセッサ x86 システムおよび x86 以外のシステムで予期しない動作をします。
それで、何が起こっているのでしょうか?命令が利用できないInterlockedCompareExchange
486 以前の CPU でも関数が確実に動作するように、アラインメント要件を設定しているのcmpxchg
でしょうか? 上記の情報に基づくと、その可能性が高いと思われますが、それに頼る前に確認しておきたいと思います。:)
それとも、アトミック性を保証するために ISA によってアライメントが要求されており、私が Intel のリファレンス マニュアルで間違った場所を調べているだけなのでしょうか?
ベストアンサー1
x86はないlock cmpxchg
命令をアトミックにするにはアライメントが必要です。ただし、良好なパフォーマンスを得るにはアライメントが不可欠です。
これは驚くことではありません。下位互換性とは、14 年前のマニュアルで作成されたソフトウェアが、今日のプロセッサでも実行できることを意味します。現代の CPU には、スプリットlock
検出は非常に高価なため、専用のパフォーマンス カウンターさえあります。(コアは、操作中は単一のキャッシュ ラインへの排他的アクセスを保持するだけでは不十分で、従来のバス ロックのような処理を実行する必要があります)。
Microsoft がなぜアライメント要件を文書化しているのかは明確ではありません。RISC アーキテクチャをサポートするためには確かに必要ですが、マルチプロセッサ x86 での予測不可能な動作という具体的な主張は有効ではない可能性があります (正確性の問題ではなく、予測不可能なパフォーマンスを意味している場合を除く)。
486以前のシステムにのみ適用されるというあなたの推測はlock cmpxchg
正しいかもしれません。そこでは、純粋なロードや純粋なストアの周りに何らかのロックを必要とするような異なるメカニズムが必要だったでしょう。(また、486にはcmpxchg
異なる、現在文書化されていないオペコード(0f a7
) からモダンなcmpxchg
(0f b1
)これは 586 Pentium で新しく追加された機能です。Windows ではcmpxchg
P5 Pentium 以降でのみ使用されていた可能性がありますが、私にはわかりません。) これにより、一部の x86 での異常が説明される可能性がありますが、最新の x86 での異常を意味するものではありません。
Intel® 64 および IA-32 アーキテクチャ ソフトウェア デベロッパーズ マニュアル
第 3 巻 (3A): システム プログラミング ガイド
2013 年 1 月8.1.2.2 ソフトウェア制御のバスロック
LOCK セマンティクスを明示的に強制するには、ソフトウェアでメモリ位置を変更するときに、次の命令に LOCK プレフィックスを使用できます。 [...]
• 交換命令 (XADD、CMPXCHG、CMPXCHG8B)。
• XCHG 命令では、LOCK プレフィックスが自動的に想定されます。
• [...][...] バス ロックの整合性は、メモリ フィールドのアラインメントの影響を受けません。 LOCK セマンティクスは、オペランド全体を更新するために必要な数のバス サイクルで適用されます。 ただし、システム パフォーマンスを向上させるには、ロックされたアクセスを自然な境界に合わせることをお勧めします。
• 8 ビット アクセスの任意の境界 (ロックされているかどうかに関係なく)。
• ロックされたワード アクセスの 16 ビット境界。
• ロックされたダブルワード アクセスの 32 ビット境界。
• ロックされたクワッドワード アクセスの 64 ビット境界。
楽しい事実:cmpxchg
それなしプレフィックスlock
はコンテキストスイッチに関して依然としてアトミックであるなので、シングルコアシステムでのマルチスレッドに使用できます。
ミスアラインメントであっても、割り込みに関してはアトミックであり (完全に前か完全に後)、ティアリングが発生する可能性があるのは他のデバイス (DMA など) によるメモリ読み取りのみです。ただし、このようなアクセスではロードとストアが分離される可能性があるため、古い Windows がシングルコア システムでより効率的な InterlockedCompareExchange にこれを使用していたとしても、正確性のためにアラインメントは必要なく、パフォーマンスのみが必要です。これがハードウェア アクセスに使用できる場合、Windows はおそらくこれを実行しないでしょう。
ライブラリ関数がlock cmpxchg
これとは別に純粋なロードを実行する必要がある場合は意味があるかもしれませんが、そうする必要はありません。(インライン化されていない場合、32 ビット バージョンはスタックから引数をロードする必要がありますが、これはプライベートであり、共有変数へのアクセスではありません。)