_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