_InterlockedCompareExchange
funzioni intrinseche
Sezione specifica Microsoft
Esegue un confronto e uno scambio interlocked.
Sintassi
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
);
Parametri
Destination
[in, out] Puntatore al valore di destinazione. Il segno viene ignorato.
Exchange
[in] Valore di Exchange. Il segno viene ignorato.
Comparand
[in] Valore da confrontare con il valore a Destination
cui punta . Il segno viene ignorato.
Valore restituito
Il valore restituito è il valore iniziale a cui punta il Destination
puntatore.
Requisiti
Intrinsic | Architettura | Intestazione |
---|---|---|
_InterlockedCompareExchange , _InterlockedCompareExchange8 , _InterlockedCompareExchange16 _InterlockedCompareExchange64 |
x86, ARM, x64, ARM64 | <intrin.h> |
_InterlockedCompareExchange_acq , _InterlockedCompareExchange_nf , , _InterlockedCompareExchange8_acq _InterlockedCompareExchange8_nf , _InterlockedCompareExchange8_rel , _InterlockedCompareExchange16_acq _InterlockedCompareExchange16_rel _InterlockedCompareExchange16_nf , , _InterlockedCompareExchange64_nf _InterlockedCompareExchange64_acq _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> |
Osservazioni:
_InterlockedCompareExchange
esegue un confronto atomico del valore a Destination
cui punta con il Comparand
valore . Se il valore Destination
è uguale al valore Comparand
, il valore Exchange
viene archiviato nell'indirizzo specificato da Destination
. In caso contrario, non esegue alcuna operazione.
_InterlockedCompareExchange
fornisce il supporto intrinseco del compilatore per la funzione Windows SDK InterlockedCompareExchange
Win32.
Esistono diverse varianti su _InterlockedCompareExchange
che variano in base ai tipi di dati che coinvolgono e se vengono usate semantiche di acquisizione o rilascio specifiche del processore.
Mentre la _InterlockedCompareExchange
funzione opera su valori integer a 32 bit long
, _InterlockedCompareExchange8
opera su valori integer a 8 bit, _InterlockedCompareExchange16
opera su valori integer a 16 bit short
e _InterlockedCompareExchange64
opera su valori interi a 64 bit. Per altre informazioni su oggetti intrinseci simili per i valori a 128 bit, vedere _InterlockedCompareExchange128
.
In tutte le piattaforme ARM usare gli intrinseci con _acq
e _rel
i suffissi per la semantica di acquisizione e rilascio, ad esempio all'inizio e alla fine di una sezione critica. Gli intrinseci ARM con un _nf
suffisso ("nessun recinto") 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 ha le sue limitazioni come base per la programmazione multithreading; viene presentato per illustrare l'uso tipico degli intrinseci interlocked. Per ottenere risultati migliori, usare l'API Windows. Per altre informazioni sulla programmazione multithreading, vedere Scrittura di un programma Win32 multithreading.
// 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
Fine sezione specifica Microsoft
Vedi anche
_InterlockedCompareExchange128
_InterlockedCompareExchangePointer
funzioni intrinseche
Intrinseci del compilatore
Parole chiave
Conflitti con il compilatore x86