_InterlockedCompareExchange
Systeminterne Funktionen
Microsoft-spezifisch
Führt einen verzahnten Vergleich und Austausch durch.
Syntax
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
);
Parameter
Destination
[in, out] Zeiger auf den Zielwert. Das Zeichen wird ignoriert.
Exchange
[in] Umrechnungswert. Das Zeichen wird ignoriert.
Comparand
[in] Wert, der mit dem Wert verglichen werden soll, der mit Destination
. Das Zeichen wird ignoriert.
Rückgabewert
Der Rückgabewert ist der Anfangswert, auf den der Destination
Zeiger verweist.
Anforderungen
Intrinsic | Aufbau | Header |
---|---|---|
_InterlockedCompareExchange , , _InterlockedCompareExchange8 _InterlockedCompareExchange16 _InterlockedCompareExchange64 |
x86, ARM, x64, ARM64 | <intrin.h> |
_InterlockedCompareExchange_acq , _InterlockedCompareExchange_nf , , _InterlockedCompareExchange_rel , _InterlockedCompareExchange8_acq , _InterlockedCompareExchange8_rel _InterlockedCompareExchange8_nf , _InterlockedCompareExchange16_acq , _InterlockedCompareExchange16_nf , , _InterlockedCompareExchange16_rel , _InterlockedCompareExchange64_acq , , _InterlockedCompareExchange64_nf _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> |
Hinweise
_InterlockedCompareExchange
führt einen atomigen Vergleich des Werts durch Destination
den Comparand
Wert aus. Wenn der Destination
-Wert gleich dem Comparand
-Wert ist, wird der Exchange
-Wert in der von Destination
angegebenen Adresse gespeichert. Andernfalls wird kein Vorgang ausgeführt.
_InterlockedCompareExchange
stellt systeminterne Compilerunterstützung für die Win32 Windows SDK-Funktion InterlockedCompareExchange
bereit.
Es gibt mehrere Variationen, _InterlockedCompareExchange
die je nach den verwendeten Datentypen variieren und ob prozessorspezifische Kauf- oder Freigabesemantik verwendet werden.
Während die _InterlockedCompareExchange
Funktion mit ganzzahligen 32-Bit-Werten long
arbeitet, _InterlockedCompareExchange8
werden 8-Bit-ganzzahlige Werte verwendet, _InterlockedCompareExchange16
mit ganzzahligen 16-Bit-Werten short
ausgeführt und _InterlockedCompareExchange64
werden auf 64-Bit-Ganzzahlwerten ausgeführt. Weitere Informationen zu ähnlichen systeminternen Werten für 128-Bit-Werte finden Sie unter _InterlockedCompareExchange128
.
Verwenden Sie auf allen ARM-Plattformen die systeminternen Mit _acq
- und _rel
Suffixe zum Abrufen und Freigeben der Semantik, z. B. am Anfang und Ende eines kritischen Abschnitts. Die systeminternen ARM-Dateien mit einem _nf
Suffix ("kein Zaun") wirken nicht als Speicherbarriere.
Die systeminternen Funktionen mit dem Suffix _np
(„no prefetch“) verhindern, dass ein möglicher Vorabrufvorgang vom Compiler eingefügt wird.
Auf Intel-Plattformen, die Hardware Lock Elision (HLE)-Anweisungen unterstützen, enthalten die systeminternen Funktionen mit den Suffixen _HLEAcquire
und _HLERelease
einen Hinweis für den Prozessor, wie die Leistung durch den Wegfall der Schreibsperre in der Hardware beschleunigt werden kann. Wenn diese systeminternen Elemente auf Plattformen aufgerufen werden, die HLE nicht unterstützen, wird der Hinweis ignoriert.
Diese Routinen sind nur als systeminterne Funktionen verfügbar.
Beispiel
Im folgenden Beispiel wird _InterlockedCompareExchange
für die einfache Low-Level-Threadsynchronisierung verwendet. Der Ansatz hat seine Grenzen als Grundlage für die Multithread-Programmierung; es wird vorgestellt, um die typische Verwendung der verriegelten Systeminternen zu veranschaulichen. Verwenden Sie für optimale Ergebnisse die Windows-API. Weitere Informationen zur Multithread-Programmierung finden Sie unter Schreiben eines Multithread-Win32-Programms.
// 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
Ende Microsoft-spezifisch
Siehe auch
_InterlockedCompareExchange128
Intrinsische _InterlockedCompareExchangePointer
-Funktionen
Intrinsische Compilerfunktionen
Schlüsselwörter
Konflikt mit dem x86-Compiler