Condividi tramite


_InterlockedCompareExchange Intrinsic Functions

Sezione specifica Microsoft

Esegue un'operazione di confronto e scambio con interlock.

long _InterlockedCompareExchange(
   long volatile * Destination,
   long Exchange,
   long Comparand
);
long _InterlockedCompareExchange_acq(
   long volatile * Destination,
   long Exchange,
   long Comparand
);
long _InterlockedCompareExchange_HLEAcquire(
   long volatile * Destination,
   long Exchange,
   long Comparand
);
long _InterlockedCompareExchange_HLERelease(
   long volatile * Destination,
   long Exchange,
   long Comparand
);
long _InterlockedCompareExchange_np(
   long volatile * Destination,
   long Exchange,
   long Comparand
);
long _InterlockedCompareExchange_rel(
   long volatile * Destination,
   long Exchange,
   long Comparand
);
char _InterlockedCompareExchange8(
   char volatile * Destination,
   char Exchange,
   char Comparand
);
char _InterlockedCompareExchange8_acq(
   char volatile * Destination,
   char Exchange,
   char Comparand
);
char _InterlockedCompareExchange8_nf(
   char volatile * Destination,
   char Exchange,
   char Comparand
);
char _InterlockedCompareExchange8_rel(
   char volatile * Destination,
   char Exchange,
   char Comparand
);
short _InterlockedCompareExchange16(
   short volatile * Destination,
   short Exchange,
   short Comparand
);
short _InterlockedCompareExchange16_acq(
   short volatile * Destination,
   short Exchange,
   short Comparand
);
short _InterlockedCompareExchange16_nf(
   short volatile * Destination,
   short Exchange,
   short Comparand
);
short _InterlockedCompareExchange16_np(
   short volatile * Destination,
   short Exchange,
   short Comparand
);
short _InterlockedCompareExchange16_rel(
   short volatile * Destination,
   short Exchange,
   short Comparand
);
__int64 _InterlockedCompareExchange64(
   __int64 volatile * Destination,
   __int64 Exchange,
   __int64 Comparand
);
__int64 _InterlockedCompareExchange64_acq(
   __int64 volatile * Destination,
   __int64 Exchange,
   __int64 Comparand
);
__int64 _InterlockedCompareExchange64_HLEAcquire (
   __int64 volatile * Destination,
   __int64 Exchange,
   __int64 Comparand
);
__int64 _InterlockedCompareExchange64_HLERelease(
   __int64 volatile * Destination,
   __int64 Exchange,
   __int64 Comparand
);
__int64 _InterlockedCompareExchange64_nf(
   __int64 volatile * Destination,
   __int64 Exchange,
   __int64 Comparand
);
__int64 _InterlockedCompareExchange64_np(
   __int64 volatile * Destination,
   __int64 Exchange,
   __int64 Comparand
);
__int64 _InterlockedCompareExchange64_rel(
   __int64 volatile * Destination,
   __int64 Exchange,
   __int64 Comparand
);

Parametri

  • [in, out] Destination
    Puntatore al valore di destinazione. Il segno viene ignorato.

  • [in] Exchange
    Valore Exchange. Il segno viene ignorato.

  • [in] Comparand
    Valore da confrontare con la destinazione. Il segno viene ignorato.

Valore restituito

Il valore restituito è il valore iniziale del puntatore Destination.

Requisiti

Funzione intrinseca

Architettura

Header

_InterlockedCompareExchange, _InterlockedCompareExchange8, _InterlockedCompareExchange16, _InterlockedCompareExchange64

x86, ARM, x64

<intrin.h>

_InterlockedCompareExchange_acq, _InterlockedCompareExchange_rel, _InterlockedCompareExchange8_acq, _InterlockedCompareExchange8_nf, _InterlockedCompareExchange8_rel,_InterlockedCompareExchange16_acq, _InterlockedCompareExchange16_nf, _InterlockedCompareExchange16_rel, _InterlockedCompareExchange64_acq, _InterlockedCompareExchange64_nf, _InterlockedCompareExchange64_rel,

ARM

<intrin.h>

_InterlockedCompareExchange_np, _InterlockedCompareExchange16_np, _InterlockedCompareExchange64_np

x64

<intrin.h>

_InterlockedCompareExchange_HLEAcquire, _InterlockedCompareExchange_HLERelease, _InterlockedCompareExchange64_HLEAcquire, _InterlockedCompareExchange64_HLERelease

x86, x64

<immintrin.h>

Note

_InterlockedCompareExchange esegue un confronto atomico del valore Destination con il valore Comparand. Se il valore Destination è uguale al valore Comparand, il valore Exchange viene archiviato nell'indirizzo specificato da Destination. In caso contrario, non viene eseguita alcuna operazione.

_InterlockedCompareExchange fornisce il supporto intrinseco del compilatore per la funzione Win32 Windows SDK InterlockedCompareExchange.

Ci sono diverse varianti di _InterlockedCompareExchange che variano in base ai tipi di dati interessati e all'uso della semantica di acquisizione o di rilascio specifica del processore.

Mentre la funzione _InterlockedCompareExchange opera su valori Long Integer, _InterlockedCompareExchange8 opera su valori Integer a 8 bit, _InterlockedCompareExchange16 opera su valori Short Integer e _InterlockedCompareExchange64 opera su valori Integer a 64 bit.

Sulle piattaforme ARM usare le funzioni intrinseche con i suffissi _acq e _rel per la semantica di acquisizione e di rilascio, ad esempio all'inizio e alla fine di una sezione critica. Le funzioni intrinseche ARM con suffisso _nf ("nessun limite") non fungono da barriera di memoria.

Le funzioni intrinseche con suffisso _np ("nessuna prelettura") impediscono l'inserimento di una possibile operazione di prelettura da parte del compilatore.

Sulle piattaforme Intel che supportano le istruzioni HLE (Hardware Lock Elision), le funzioni intrinseche con suffissi _HLEAcquire e _HLERelease includono un hint per il processore che consente di accelerare le prestazioni eliminando un passaggio di blocco scrittura nell'hardware. Se queste funzioni intrinseche vengono chiamate su piattaforme che non supportano HLE, l'hint viene ignorato.

Queste routine sono disponibili solo come funzioni intrinseche.

Esempio

Nell'esempio seguente, _InterlockedCompareExchange viene usato per la sincronizzazione semplice di thread di basso livello. L'approccio presenta alcune limitazioni come base per la programmazione multithreading. Viene presentato per illustrare l'uso tipico delle funzioni intrinseche interlocked. Per ottenere risultati migliori, usare l'API Windows. Per altre informazioni sulla programmazione multithreading, vedere Scrittura di un programma multithread Win32.

// intrinExample.cpp
// compile with: /EHsc /O2
// Simple example of using _Interlocked* intrinsics to
// do manual synchronization
//
// Add [-DSKIP_LOCKING] to the command line to disable
// the locking. This will cause the threads to execute out
// of sequence.

#define _CRT_RAND_S
 
#include "windows.h"
 
#include <iostream>
#include <queue>
#include <intrin.h>
 
using namespace std;
 
// --------------------------------------------------------------------
 
// if defined, will not do any locking on shared data
//#define SKIP_LOCKING
 
// A common way of locking using _InterlockedCompareExchange.
// Please refer to other sources for a discussion of the many issues
// involved. For example, this particular locking scheme performs well 
// when lock contention is low, as the while loop overhead is small and
// locks are acquired very quickly, but degrades as many callers want
// the lock and most threads are doing a lot of interlocked spinning.
// There are also no guarantees that a caller will ever acquire the
// lock.
namespace MyInterlockedIntrinsicLock
{
    typedef unsigned LOCK, *PLOCK;
 
#pragma intrinsic(_InterlockedCompareExchange, _InterlockedExchange)
 
    enum {LOCK_IS_FREE = 0, LOCK_IS_TAKEN = 1};
 
    void Lock(PLOCK pl) 
    {
#if !defined(SKIP_LOCKING)
        // If *pl == LOCK_IS_FREE, it is set to LOCK_IS_TAKEN
        // atomically, so only 1 caller gets the lock.
        // If *pl == LOCK_IS_TAKEN,
        // the result is LOCK_IS_TAKEN, and the while loop keeps spinning.
        while (_InterlockedCompareExchange((long *)pl,
                                           LOCK_IS_TAKEN, // exchange
                                           LOCK_IS_FREE)  // comparand
               == LOCK_IS_TAKEN)
        {
            // spin!
        }
        // This will also work.
        //while (_InterlockedExchange(pl, LOCK_IS_TAKEN) == 
        //                             LOCK_IS_TAKEN)
        //{
        //    // spin!
        //}
 
        // At this point, the lock is acquired.
#endif
    }
 
    void Unlock(PLOCK pl) {
#if !defined(SKIP_LOCKING)
        _InterlockedExchange((long *)pl, LOCK_IS_FREE);
#endif
    }
}
 
// ------------------------------------------------------------------
 
// Data shared by threads
 
queue<int> SharedQueue;
MyInterlockedIntrinsicLock::LOCK SharedLock;
int TicketNumber;
 
// ------------------------------------------------------------------
 
DWORD WINAPI
ProducerThread(
    LPVOID unused
    )
{
    unsigned int randValue;
    while (1) {
        // Acquire shared data. Enter critical section.
        MyInterlockedIntrinsicLock::Lock(&SharedLock);
 
        //cout << ">" << TicketNumber << endl;
        SharedQueue.push(TicketNumber++);
 
        // Release shared data. Leave critical section.
        MyInterlockedIntrinsicLock::Unlock(&SharedLock);

        rand_s(&randValue);
        Sleep(randValue % 20);
    }
 
    return 0;
}
 
DWORD WINAPI
ConsumerThread(
    LPVOID unused
    )
{
    while (1) {
        // Acquire shared data. Enter critical section
        MyInterlockedIntrinsicLock::Lock(&SharedLock);
 
        if (!SharedQueue.empty()) {
            int x = SharedQueue.front();
            cout << "<" << x << endl;
            SharedQueue.pop();
        }
 
        // Release shared data. Leave critical section
        MyInterlockedIntrinsicLock::Unlock(&SharedLock);

        unsigned int randValue;
        rand_s(&randValue);
        Sleep(randValue % 20);
    }
    return 0;
}
 
 
int main(
    void
    )
{
    const int timeoutTime = 500;
    int unused1, unused2;
    HANDLE threads[4];
 
    // The program creates 4 threads:
    // two producer threads adding to the queue
    // and two consumers taking data out and printing it.
    threads[0] = CreateThread(NULL,
                              0,
                              ProducerThread,
                              &unused1,
                              0,
                              (LPDWORD)&unused2);
 
    threads[1] = CreateThread(NULL,
                              0,
                              ConsumerThread,
                              &unused1,
                              0,
                              (LPDWORD)&unused2);
 
    threads[2] = CreateThread(NULL,
                              0,
                              ProducerThread,
                              &unused1,
                              0,
                              (LPDWORD)&unused2);
 
    threads[3] = CreateThread(NULL,
                              0,
                              ConsumerThread,
                              &unused1,
                              0,
                              (LPDWORD)&unused2);
 
    WaitForMultipleObjects(4, threads, TRUE, timeoutTime);
 
    return 0;
}
  

Vedere anche

Riferimenti

_InterlockedCompareExchange128

Funzioni intrinseche _InterlockedCompareExchangePointer

Intrinseci del compilatore

Parole chiave C++

Conflitti con il compilatore x86