Intelドキュメント は言う
この命令を
LOCK
プレフィックスとともに使用すると、命令をアトミックに実行できます。
私の質問は
CMPXCHG
はメモリアドレスで動作できますか?ドキュメントからはそうではないようですが、メモリアドレスではなく、レジスタ内の実際のVALUEでのみ機能することを誰かが確認できますか?
CMPXCHG
がアトミックではなく、高水準言語レベルのCASをLOCK CMPXCHG
(LOCK
プレフィックス付き)で実装する必要がある場合、そのような命令を導入する目的は何ですか?
高レベルのロックと、たまたまLOCK
という名前の低レベルのCPU機能を混同しています。
ロックフリーアルゴリズムが回避しようとする高レベルのロックは、実行に任意の時間がかかる可能性のある任意のコードフラグメントを保護できるため、これらのロックは、ロックが使用可能になるまでスレッドを待機状態にする必要があります。これは、コストのかかる操作です。待機中のスレッドのキューを維持することを意味します。
これは、単一の命令のみを保護するCPU LOCK
プレフィックス機能とはまったく異なるものであり、したがって、その単一の命令の間だけ他のスレッドを保持する可能性があります。これはCPU自体によって実装されるため、追加のソフトウェア作業は必要ありません。
したがって、ロックフリーアルゴリズムを開発する際の課題は、同期を完全に削除することではなく、コードのクリティカルセクションをCPU自体によって提供される単一のアトミック操作に減らすことです。
あなたが本当に求めているのは、次のような部分のようです。
lock
プレフィックスがメモリオペランドを使用してcmpxchg
に暗黙的に含まれないのはなぜですか、xchg
の場合と同様 ?
簡単な答え(他の人が与えた)は、Intelがそれをこのように設計したということです。しかし、これは質問につながります:
なぜインテルはそれをしたのですか?
cmpxchg
なしのlock
のユースケースはありますか?
シングルCPUシステムでは、cmpxchg
is他のスレッド、または同じCPUコアで実行されている他のコードに対してアトミックです。 (ただし、メモリマップドI/Oデバイスや、通常のメモリのDMA読み取りを行うデバイスのような「システム」オブザーバーには当てはまらないため、lock cmpxchg
はユニプロセッサCPU設計にも関連していました)。
コンテキストスイッチは割り込みでのみ発生し、割り込みは命令の前または後に発生し、途中では発生しません。同じCPUで実行されているコードは、cmpxchg
が完全に実行されたか、まったく実行されていないかを認識します。
たとえば、Linuxカーネルは通常SMPをサポートしてコンパイルされているため、アトミックCASにはlock cmpxchg
を使用します。ただし、シングルプロセッサシステムで起動すると、lock
nop
が多く実行されるため、コードがインライン化されたすべての場所で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
の場合以外で役立ちます。)
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)が生成される可能性があります。