_InterlockedCompareExchange
fonctions intrinsèques
Section spécifique à Microsoft
Effectue une comparaison et un échange interblocés.
Syntaxe
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_nf(
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
Destination
[in, out] Pointeur vers la valeur de destination. Le signe est ignoré.
Exchange
[in] Valeur d’échange. Le signe est ignoré.
Comparand
[in] Valeur à comparer à la valeur pointée par Destination
. Le signe est ignoré.
Valeur retournée
La valeur de retour est la valeur initiale pointée par le Destination
pointeur.
Spécifications
Intrinsic | Architecture | En-tête |
---|---|---|
_InterlockedCompareExchange , , _InterlockedCompareExchange8 _InterlockedCompareExchange16 , ,_InterlockedCompareExchange64 |
x86, ARM, x64, ARM64 | <intrin.h> |
_InterlockedCompareExchange_acq , , _InterlockedCompareExchange_nf , _InterlockedCompareExchange8_acq , , _InterlockedCompareExchange8_rel _InterlockedCompareExchange64_acq _InterlockedCompareExchange64_nf _InterlockedCompareExchange16_acq _InterlockedCompareExchange16_rel _InterlockedCompareExchange16_nf _InterlockedCompareExchange8_nf _InterlockedCompareExchange_rel _InterlockedCompareExchange64_rel |
ARM, ARM64 | <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 pointée à l’aide Destination
de la Comparand
valeur. Si la valeur Destination
est égale à la valeur Comparand
, la valeur Exchange
est stockée dans l'adresse spécifiée par Destination
. Sinon, aucune opération n’est effectuée.
_InterlockedCompareExchange
fournit la prise en charge intrinsèque du compilateur pour la fonction sdk InterlockedCompareExchange
Windows Win32.
Plusieurs variantes _InterlockedCompareExchange
varient en fonction des types de données qu’ils impliquent et indiquent si la sémantique d’acquisition ou de mise en production spécifique au processeur est utilisée.
Bien que la _InterlockedCompareExchange
fonction fonctionne sur des valeurs entières 32 bits long
, _InterlockedCompareExchange8
fonctionne sur des valeurs entières 8 bits, _InterlockedCompareExchange16
fonctionne sur des valeurs entières 16 bits short
et _InterlockedCompareExchange64
fonctionne sur des valeurs entières 64 bits. Pour plus d’informations sur les intrinsèques similaires pour les valeurs 128 bits, consultez _InterlockedCompareExchange128
.
Sur toutes les plateformes ARM, utilisez les intrinsèques avec _acq
et _rel
suffixes pour acquérir et libérer la sémantique, comme au début et à la fin d’une section critique. Les intrinsèques ARM avec un _nf
suffixe (« sans clôture ») ne font pas office de barrière de 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 intrinsèques sont appelées sur des plateformes qui ne prennent pas en charge HLE, l’indicateur est ignoré.
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 présente ses limitations en tant que base pour la programmation multithread ; il est présenté pour illustrer l’utilisation typique des intrinsèques interblocé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.
// 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;
}
<0
<1
<2
<3
<4
<5
<6
<7
<8
<9
<10
<11
<12
<13
<14
<15
<16
<17
<18
<19
<20
<21
<22
<23
<24
<25
<26
<27
<28
<29
FIN de la section spécifique à Microsoft
Voir aussi
_InterlockedCompareExchange128
Fonctions intrinsèques _InterlockedCompareExchangePointer
Intrinsèques du compilateur
Mots clés
Conflits avec le compilateur x86