_InterlockedCompareExchange128 intrinsic functions

Microsoft Specific

Performs a 128-bit interlocked compare and exchange.

Syntax

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
);

Parameters

Destination
[in, out] Pointer to the destination, which is an array of two 64-bit integers considered as a 128-bit field. The destination data must be 16-byte aligned to avoid a general protection fault.

ExchangeHigh
[in] A 64-bit integer that may be exchanged with the high part of the destination.

ExchangeLow
[in] A 64-bit integer that may be exchanged with the low part of the destination.

ComparandResult
[in, out] Pointer to an array of two 64-bit integers (considered as a 128-bit field) to compare with the destination. On output, this array is overwritten with the original value of the destination.

Return value

1 if the 128-bit comparand equals the original value of the destination. ExchangeHigh and ExchangeLow overwrite the 128-bit destination.

0 if the comparand doesn't equal the original value of the destination. The value of the destination is unchanged, and the value of the comparand is overwritten with the value of the destination.

Requirements

Intrinsic Architecture
_InterlockedCompareExchange128 x64, ARM64
_InterlockedCompareExchange128_acq, _InterlockedCompareExchange128_nf, _InterlockedCompareExchange128_rel ARM64
_InterlockedCompareExchange128_np x64

Header file <intrin.h>

Remarks

The _InterlockedCompareExchange128 intrinsic generates the cmpxchg16b instruction (with the lock prefix) to perform a 128-bit locked compare and exchange. Early versions of AMD 64-bit hardware don't support this instruction. To check for hardware support for the cmpxchg16b instruction, call the __cpuid intrinsic with InfoType=0x00000001 (standard function 1). Bit 13 of CPUInfo[2] (ECX) is 1 if the instruction is supported.

Note

The value of ComparandResult is always overwritten. After the lock instruction, this intrinsic immediately copies the initial value of Destination to ComparandResult. For this reason, ComparandResult and Destination should point to separate memory locations to avoid unexpected behavior.

Although you can use _InterlockedCompareExchange128 for low-level thread synchronization, you don't need to synchronize over 128 bits if you can use smaller synchronization functions (such as the other _InterlockedCompareExchange intrinsics) instead. Use _InterlockedCompareExchange128 if you want atomic access to a 128-bit value in memory.

If you run code that uses the intrinsic on hardware that doesn't support the cmpxchg16b instruction, the results are unpredictable.

On ARM platforms, use the intrinsics with _acq and _rel suffixes for acquire and release semantics, such as at the beginning and end of a critical section. The ARM intrinsics with an _nf ("no fence") suffix don't act as a memory barrier.

The intrinsics with an _np ("no prefetch") suffix prevent a possible prefetch operation from being inserted by the compiler.

This routine is available only as an intrinsic.

Example

This example uses _InterlockedCompareExchange128 to replace the high word of an array of two 64-bit integers with the sum of its high and low words and to increment the low word. The access to the BigInt.Int array is atomic, but this example uses a single thread and ignores the locking for simplicity.

// 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

END Microsoft Specific

See also

Compiler intrinsics
_InterlockedCompareExchange intrinsic functions
Conflicts with the x86 Compiler