_InterlockedCompareExchange
funkcje wewnętrzne
Specyficzne dla firmy Microsoft
Czy połączone porównanie i wymiana.
Składnia
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
);
Parametry
Destination
[in, out] Wskaźnik do wartości docelowej. Znak jest ignorowany.
Exchange
[in] Wartość wymiany. Znak jest ignorowany.
Comparand
[in] Wartość do porównania z wartością wskazywaną przez Destination
. Znak jest ignorowany.
Wartość zwracana
Wartość zwracana jest początkową wartością wskazywaną Destination
przez wskaźnik.
Wymagania
Wewnętrzne | Architektura | Nagłówek |
---|---|---|
_InterlockedCompareExchange , _InterlockedCompareExchange8 , _InterlockedCompareExchange16 , _InterlockedCompareExchange64 |
x86, ARM, x64, ARM64 | <intrin.h> |
_InterlockedCompareExchange_acq , _InterlockedCompareExchange_nf , _InterlockedCompareExchange_rel , _InterlockedCompareExchange8_acq , _InterlockedCompareExchange8_nf , _InterlockedCompareExchange8_rel ,_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> |
Uwagi
_InterlockedCompareExchange
wykonuje niepodzielne porównanie wartości wskazywanej przez Destination
wartość Comparand
. Destination
Jeśli wartość jest równa Comparand
wartości, Exchange
wartość jest przechowywana w adresie określonym przez Destination
. W przeciwnym razie nie wykonuje żadnej operacji.
_InterlockedCompareExchange
zapewnia wewnętrzną obsługę kompilatora dla funkcji zestawu Windows SDK InterlockedCompareExchange
systemu Windows Win32.
Istnieje kilka odmian, _InterlockedCompareExchange
które różnią się w zależności od typów danych, które obejmują i czy są używane semantyka pozyskiwania lub wydawania specyficzne dla procesora.
_InterlockedCompareExchange
Chociaż funkcja działa na 32-bitowych long
wartościach całkowitych, _InterlockedCompareExchange8
działa na 8-bitowych wartościach całkowitych, _InterlockedCompareExchange16
działa na 16-bitowych wartościach całkowitych i _InterlockedCompareExchange64
działa na 64-bitowych short
wartościach całkowitych. Aby uzyskać więcej informacji na temat podobnych wewnętrznych wartości 128-bitowych, zobacz _InterlockedCompareExchange128
.
Na wszystkich platformach ARM użyj funkcji wewnętrznych z sufiksami _acq
i _rel
do uzyskiwania i semantyki wydań, takich jak na początku i na końcu sekcji krytycznej. Funkcje wewnętrzne arm z sufiksem _nf
("bez ogrodzenia") nie działają jako bariera pamięci.
Funkcje wewnętrzne z sufiksem _np
("brak pobierania wstępnego") uniemożliwiają wstawienie możliwej operacji pobierania wstępnego przez kompilator.
Na platformach Intel, które obsługują instrukcje dotyczące blokady sprzętu Elision (HLE), funkcje wewnętrzne z sufiksami _HLEAcquire
zawierają _HLERelease
wskazówkę dla procesora, który może przyspieszyć wydajność, eliminując krok zapisu blokady w sprzęcie. Jeśli te funkcje wewnętrzne są wywoływane na platformach, które nie obsługują HLE, wskazówka jest ignorowana.
Te procedury są dostępne tylko jako funkcje wewnętrzne.
Przykład
W poniższym przykładzie _InterlockedCompareExchange
jest używana do prostej synchronizacji wątków niskiego poziomu. Podejście ma swoje ograniczenia jako podstawę do programowania wielowątkowego; przedstawia się, aby zilustrować typowe użycie połączonych wewnętrznych elementów. Aby uzyskać najlepsze wyniki, użyj interfejsu API systemu Windows. Aby uzyskać więcej informacji na temat programowania wielowątkowego, zobacz Pisanie wielowątkowego programu 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.
// 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
END Microsoft Specific
Zobacz też
_InterlockedCompareExchange128
_InterlockedCompareExchangePointer
funkcje wewnętrzne
Funkcje wewnętrzne kompilatora
Słowa kluczowe
Konflikty z kompilatorem x86
Opinia
https://aka.ms/ContentUserFeedback.
Dostępne już wkrótce: W 2024 r. będziemy stopniowo wycofywać zgłoszenia z serwisu GitHub jako mechanizm przesyłania opinii na temat zawartości i zastępować go nowym systemem opinii. Aby uzyskać więcej informacji, sprawdź:Prześlij i wyświetl opinię dla