web-dev-qa-db-ja.com

x86 CMPXCHGはアトミックですか?もしそうなら、なぜLOCKが必要なのですか?

Intelドキュメント は言う

この命令をLOCKプレフィックスとともに使用すると、命令をアトミックに実行できます。

私の質問は

  1. CMPXCHGはメモリアドレスで動作できますか?ドキュメントからはそうではないようですが、メモリアドレスではなく、レジスタ内の実際のVALUEでのみ機能することを誰かが確認できますか?

  2. CMPXCHGがアトミックではなく、高水準言語レベルのCASをLOCK CMPXCHGLOCKプレフィックス付き)で実装する必要がある場合、そのような命令を導入する目的は何ですか?

13
Alex Suo

高レベルのロックと、たまたまLOCKという名前の低レベルのCPU機能を混同しています。

ロックフリーアルゴリズムが回避しようとする高レベルのロックは、実行に任意の時間がかかる可能性のある任意のコードフラグメントを保護できるため、これらのロックは、ロックが使用可能になるまでスレッドを待機状態にする必要があります。これは、コストのかかる操作です。待機中のスレッドのキューを維持することを意味します。

これは、単一の命令のみを保護するCPU LOCKプレフィックス機能とはまったく異なるものであり、したがって、その単一の命令の間だけ他のスレッドを保持する可能性があります。これはCPU自体によって実装されるため、追加のソフトウェア作業は必要ありません。

したがって、ロックフリーアルゴリズムを開発する際の課題は、同期を完全に削除することではなく、コードのクリティカルセクションをCPU自体によって提供される単一のアトミック操作に減らすことです。

16
Holger

あなたが本当に求めているのは、次のような部分のようです。

lockプレフィックスがメモリオペランドを使用してcmpxchgに暗黙的に含まれないのはなぜですか、 xchgの場合と同様

簡単な答え(他の人が与えた)は、Intelがそれをこのように設計したということです。しかし、これは質問につながります:

なぜインテルはそれをしたのですか? cmpxchgなしのlockのユースケースはありますか?

シングルCPUシステムでは、cmpxchgis他のスレッド、または同じCPUコアで実行されている他のコードに対してアトミックです。 (ただし、メモリマップドI/Oデバイスや、通常のメモリのDMA読み取りを行うデバイスのような「システム」オブザーバーには当てはまらないため、lock cmpxchgはユニプロセッサCPU設計にも関連していました)。

コンテキストスイッチは割り込みでのみ発生し、割り込みは命令の前または後に発生し、途中では発生しません。同じCPUで実行されているコードは、cmpxchgが完全に実行されたか、まったく実行されていないかを認識します


たとえば、Linuxカーネルは通常SMPをサポートしてコンパイルされているため、アトミックCASにはlock cmpxchgを使用します。ただし、シングルプロセッサシステムで起動すると、locknopが多く実行されるため、コードがインライン化されたすべての場所でnopプレフィックスがcmpxchgにパッチされます。 lock cmpxchgよりも高速です。詳細については、こちらをご覧ください Linuxの「SMP代替」システムに関するLWNの記事 。 2番目のCPUをホットプラグする前に、lockプレフィックスにパッチバックすることもできます。

ユニプロセッサシステムでの単一命令のアトミック性についての詳細を読む この回答では 、および @ supercatの回答+コメントnum++int numに対してアトミックである可能性があります。アトミック性が実際にどのように機能するかについての多くの詳細については 私の答え を参照してください/ lock cmpxchgのような読み取り-変更-書き込み命令に実装されています。


(これと同じ理由がcmpxchg8b/cmpxchg16b、およびxaddにも当てはまります。これらは通常、同期/アトミック操作にのみ使用され、シングルスレッドコードの実行速度を上げるためではありません。明らかにメモリ-宛先add [mem], regは、lock add [mem], regの場合以外で役立ちます。)

27
Peter Cordes

LOCKプレフィックスは、現在のコマンドのメモリアクセスをロックして、CPUパイプラインにある他のコマンドがこの時点でメモリにアクセスできるようにするためのものです。 LOCKプレフィックスを使用すると、同時に実行される他のコマンドのメモリアクセスが原因で、CPUパイプライン内の別のコマンドによってコマンドの実行が中断されることはありません。 INTELのマニュアルには次のように書かれています。

LOCKプレフィックスは、次の命令と、宛先オペランドがメモリオペランドである命令の形式にのみ付加できます:ADD、ADC、AND、BTC、BTR、BTS、CMPXCHG、CMPXCH8B、CMPXCHG16B、DEC、INC 、NEG、NOT、OR、SBB、SUB、XOR、XADD、およびXCHG。これらの命令のいずれかでLOCKプレフィックスが使用され、ソースオペランドがメモリオペランドである場合、未定義のオペコード例外(#UD)が生成される可能性があります。

2
Van Uitkon