_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