Partager via


fonctions intrinsèques de _InterlockedCompareExchange

Section spécifique à Microsoft

Effectue une comparaison et un échange verrouillés.

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

Paramètres

  • [in, out] Destination
    Pointeur vers la valeur de destination. Le signe est ignoré.

  • [in] Exchange
    Valeur d'échange. Le signe est ignoré.

  • [in] Comparand
    Valeur à comparer à la destination. Le signe est ignoré.

Valeur de retour

La valeur de retour est la valeur initiale du pointeur Destination.

Configuration requise

Intrinsèque

Architecture

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>

Notes

_InterlockedCompareExchange effectue une comparaison atomique de la valeur Destination à la valeur Comparand. Si la valeur Destination est égale à la valeur Comparand, la valeur Exchange est stockée dans l'adresse spécifiée par Destination. Dans le cas contraire, aucune opération n'est effectuée.

_InterlockedCompareExchange fournit une prise en charge des intrinsèques du compilateur pour la fonction Win32 Kit de développement logiciel Windows InterlockedCompareExchange.

Il existe plusieurs variantes de _InterlockedCompareExchange qui varient selon les types de données qu'elles impliquent et l'utilisation d'une sémantique acquire ou release spécifique au processeur.

La fonction _InterlockedCompareExchange opère sur les valeurs entières longues, _InterlockedCompareExchange8 sur les valeurs entières de 8 bits, _InterlockedCompareExchange16 sur les valeurs entières courtes et _InterlockedCompareExchange64 sur les valeurs entières de 64 bits.

Sur les plateformes ARM, utilisez les intrinsèques avec les suffixes _acq et _rel pour la sémantique Acquire et Release, comme au début et à la fin d'une section critique. Les fonctions intrinsèques ARM avec un suffixe _nf (pour « no fence », « pas de délimitation ») n'agissent pas comme une barrière mémoire.

Les fonctions intrinsèques avec un suffixe _np (pour « no prefetch », « pas de prérécupération ») empêchent l'insertion par le compilateur d'une possible opération de prérécupération.

Sur les plateformes Intel qui prennent en charge les instructions HLE (Hardware Lock Elision), les fonctions intrinsèques avec les suffixes _HLEAcquire et _HLERelease comprennent une indication pour le processeur qui peut accélérer les performances en éliminant une étape d'écriture de verrou dans le matériel. Si ces fonctions intrinsèques sont appelées sur des plateformes qui ne prennent pas en charge HLE, l'indication est ignorée.

Ces routines sont disponibles seulement comme fonctions intrinsèques.

Exemple

Dans l'exemple suivant, _InterlockedCompareExchange est utilisé pour la synchronisation simple des threads de bas niveau. L'approche a ses limites comme base pour la programmation multithread ; elle est présentée pour illustrer l'utilisation standard des intrinsèques verrouillées. Pour obtenir de meilleurs résultats, utilisez l'API Windows. Pour plus d'informations sur la programmation multithread, consultez Écriture d'un programme Win32 multithread.

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

Voir aussi

Référence

_InterlockedCompareExchange128

fonctions intrinsèques de _InterlockedCompareExchangePointer

intrinsèques du compilateur

Mots clés C++

Conflits avec le compilateur x86