Compartilhar via


Funções intrínsecas _InterlockedCompareExchange128

Seção específica da Microsoft

Executa uma comparação e troca interconectada de 128 bits.

Sintaxe

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

Parâmetros

Destino
[in, out] Ponteiro para o destino, que é uma matriz de dois inteiros de 64 bits considerado como um campo de 128 bits. Os dados de destino precisam estar alinhados a 16 bytes para evitar uma falha de proteção geral.

ExchangeHigh
[in] Um inteiro de 64 bits que pode ser trocado com a parte alta do destino.

ExchangeLow
[in] Um inteiro de 64 bits que pode ser trocado com a parte baixa do destino.

ComparandResult
[in, out] Ponteiro para uma matriz de dois inteiros de 64 bits (considerado um campo de 128 bits) para comparar com o destino. Na saída, essa matriz é substituída com o valor original do destino.

Valor retornado

1 se a comparação de 128 bits for igual ao valor original do destino. ExchangeHigh e ExchangeLow substituem o destino de 128 bits.

0 se o comparand não for igual ao valor original do destino. O valor do destino é inalterado e o comparand é substituído com o valor do destino.

Requisitos

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

Arquivo de cabeçalho<intrin.h>

Comentários

O intrínseco _InterlockedCompareExchange128 gera a instrução cmpxchg16b (com o prefixo lock) para executar uma comparação e troca bloqueada em 128 bits. As versões iniciais do hardware AMD de 64 bits não dão suporte a esta instrução. Para verificar se há suporte de hardware para a instrução cmpxchg16b, chame o intrínseco __cpuid com InfoType=0x00000001 (standard function 1). O bit 13 de CPUInfo[2] (ECX) será 1 se a instrução for compatível.

Observação

O valor de ComparandResult é sempre substituído. Após a instrução lock, esse intrínseco copia imediatamente o valor inicial de Destination para ComparandResult. Por esse motivo, ComparandResult e Destination deve apontar para locais de memória separados para evitar um comportamento inesperado.

Embora você possa usar _InterlockedCompareExchange128 para sincronização de thread de nível baixo, não será necessário sincronizar mais de 128 bits se você puder usar funções de sincronização menores (como os outros intrínsecos _InterlockedCompareExchange). Use _InterlockedCompareExchange128 se você quiser acesso atômico a um valor de 128 bits na memória.

Se você executar código que usa o intrínseco em hardware que não dá suporte à instrução cmpxchg16b, os resultados serão imprevisíveis.

Em plataformas ARM, use intrínsecos com os sufixos _acq e _rel para semântica de aquisição e liberação, como no início e no final de uma seção crítica. Os intrínsecos de ARM com um sufixo _nf ("no fence") não funcionam como uma barreira de memória.

Intrínsecos com um sufixo _np ("no prefetch") impedem que uma possível operação de pré-busca seja inserida pelo compilador.

Essa rotina só está disponível como intrínseca.

Exemplo

Este exemplo usa _InterlockedCompareExchange128 para substituir a palavra alta de uma matriz de dois inteiros de 64 bits pela soma de suas palavras altas e baixas e incrementar a palavra baixa. O acesso à matriz BigInt.Int é atômico, mas este exemplo usa apenas um thread e ignora o bloqueio para simplificar.

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

Fim da seção específica da Microsoft

Confira também

Intrínsecos do compilador
Funções intrínsecas _InterlockedCompareExchange
conflitos com o compilador x86