_InterlockedCompareExchange128 組み込み関数
Microsoft 固有の仕様
128 ビットのインタロックされた比較と交換を実行します。
構文
unsigned char _InterlockedCompareExchange128(
__int64 volatile * Destination,
__int64 ExchangeHigh,
__int64 ExchangeLow,
__int64 * ComparandResult
);
unsigned char _InterlockedCompareExchange128_acq(
__int64 volatile * Destination,
__int64 ExchangeHigh,
__int64 ExchangeLow,
__int64 * ComparandResult
);
unsigned char _InterlockedCompareExchange128_nf(
__int64 volatile * Destination,
__int64 ExchangeHigh,
__int64 ExchangeLow,
__int64 * ComparandResult
);
unsigned char _InterlockedCompareExchange128_np(
__int64 volatile * Destination,
__int64 ExchangeHigh,
__int64 ExchangeLow,
__int64 * ComparandResult
);
unsigned char _InterlockedCompareExchange128_rel(
__int64 volatile * Destination,
__int64 ExchangeHigh,
__int64 ExchangeLow,
__int64 * ComparandResult
);
パラメーター
宛先
[in、out] 2 つの 64 ビット整数の配列 (128 ビット フィールドと見なされます) である宛先を指すポインター。 一般保護違反を回避するには、宛先データが 16 バイトにアラインされている必要があります。
ExchangeHigh
[in] 宛先の上位部分と交換できる 64 ビット整数。
ExchangeLow
[in] 宛先の下位部分と交換できる 64 ビット整数。
ComparandResult
[in、out] 宛先と比較する、2 つの 64 ビット整数の配列 (128 ビット フィールドと見なされます) を指すポインター。 出力時、この配列は宛先の元の値で上書きされます。
戻り値
128 ビットの比較対照値が宛先の元の値と等しい場合は 1。 ExchangeHigh
および ExchangeLow
では 128 ビットの宛先が上書きされます。
比較対照値が宛先の元の値と等しくない場合は 0。 宛先の値は変更されず、比較対象値は宛先の値で上書きされます。
要件
Intrinsic | Architecture |
---|---|
_InterlockedCompareExchange128 |
x64、ARM64 |
ARM64 | |
_InterlockedCompareExchange128_np |
x64 |
ヘッダー ファイル<intrin.h>
解説
_InterlockedCompareExchange128
組み込みでは、128 ビットのロックされた比較および交換を実行する (lock
プレフィックスの付いた) cmpxchg16b
命令が生成されます。 AMD 64 ビット ハードウェアの初期バージョンでは、この命令はサポートされていません。 cmpxchg16b
命令のハードウェア サポートを確認するには、InfoType=0x00000001 (standard function 1)
で __cpuid
組み込みを呼び出します。 命令がサポートされている場合、CPUInfo[2]
(ECX) のビット 13 は 1 になります。
Note
ComparandResult
の値は常に上書きされます。 lock
命令の後、この組み込みでは、Destination
の初期値が即座に ComparandResult
にコピーされます。 そのため、予期しない動作を回避するために、ComparandResult
と Destination
は別々のメモリ位置を指す必要があります。
_InterlockedCompareExchange128
は低レベルのスレッド同期に使用できますが、代わりにより小さな同期関数 (他の _InterlockedCompareExchange
組み込みなど) を使用できる場合は 128 ビットを超えて同期する必要がありません。 _InterlockedCompareExchange128
は、メモリ内の 128 ビット値にアトミック アクセスする場合に使用してください。
組み込みが使用されているコードを cmpxchg16b
命令がサポートされないハードウェアで実行すると、結果は予測できません。
ARM プラットフォームでは、クリティカル セクションの最初と最後などでの取得と解放のセマンティクスのために、_acq
および _rel
サフィックスの付いた組み込みを使用します。 ARM の組込み関数で _nf
("no fence") のサフィックスを持つものは、メモリ バリアとして機能しません。
組み込みに _np
("プリフェッチなし") サフィックスが付いていると、コンパイラによってプリフェッチ操作が挿入される可能性がなくなります。
このルーチンは、組み込みとしてのみ使用できます。
例
この例では、_InterlockedCompareExchange128
を使用して、2 つの 64 ビット整数の配列の上位ワードをその上位ワードと下位ワードの合計に置き換え、下位ワードをインクリメントします。 BigInt.Int
配列へのアクセスはアトミックですが、この例では単一のスレッドを使用し、わかりやすくするためにロックを無視しています。
// cmpxchg16b.c
// processor: x64
// compile with: /EHsc /O2
#include <stdio.h>
#include <intrin.h>
typedef struct _LARGE_INTEGER_128 {
__int64 Int[2];
} LARGE_INTEGER_128, *PLARGE_INTEGER_128;
volatile LARGE_INTEGER_128 BigInt;
// This AtomicOp() function atomically performs:
// BigInt.Int[1] += BigInt.Int[0]
// BigInt.Int[0] += 1
void AtomicOp ()
{
LARGE_INTEGER_128 Comparand;
Comparand.Int[0] = BigInt.Int[0];
Comparand.Int[1] = BigInt.Int[1];
do {
; // nothing
} while (_InterlockedCompareExchange128(BigInt.Int,
Comparand.Int[0] + Comparand.Int[1],
Comparand.Int[0] + 1,
Comparand.Int) == 0);
}
// In a real application, several threads contend for the value
// of BigInt.
// Here we focus on the compare and exchange for simplicity.
int main(void)
{
BigInt.Int[1] = 23;
BigInt.Int[0] = 11;
AtomicOp();
printf("BigInt.Int[1] = %d, BigInt.Int[0] = %d\n",
BigInt.Int[1],BigInt.Int[0]);
}
BigInt.Int[1] = 34, BigInt.Int[0] = 12
Microsoft 固有の仕様はここまで