Поделиться через


_InterlockedCompareExchange Intrinsic Functions

Блок, относящийся только к системам Microsoft

Выполняет заблокированное сравнение и обмен.

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_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
);

Параметры

  • [in, out] Destination
    Указатель на значение назначения. Знак игнорируется.

  • [in] Exchange
    Значение для обмена. Знак игнорируется.

  • [in] Comparand
    Значение для сравнения со значением назначения. Знак игнорируется.

Возвращаемое значение

Начальное значение является значением, возвращаемым указателем Destination.

Требования

Встроенная функция

Архитектура

Header

_InterlockedCompareExchange, _InterlockedCompareExchange8, _InterlockedCompareExchange16, _InterlockedCompareExchange64

x86, ARM, x64

<intrin.h>

_InterlockedCompareExchange_acq, _InterlockedCompareExchange_rel, _InterlockedCompareExchange8_acq, _InterlockedCompareExchange8_nf, _InterlockedCompareExchange8_rel,_InterlockedCompareExchange16_acq, _InterlockedCompareExchange16_nf, _InterlockedCompareExchange16_rel, _InterlockedCompareExchange64_acq, _InterlockedCompareExchange64_nf, _InterlockedCompareExchange64_rel,

ARM

<intrin.h>

_InterlockedCompareExchange_np, _InterlockedCompareExchange16_np, _InterlockedCompareExchange64_np

x64

<intrin.h>

_InterlockedCompareExchange_HLEAcquire, _InterlockedCompareExchange_HLERelease, _InterlockedCompareExchange64_HLEAcquire, _InterlockedCompareExchange64_HLERelease

x86, x64

<immintrin.h>

Заметки

_InterlockedCompareExchange выполняет атомарное сравнение значения Destination со значением Comparand. Если значение Destination равно значению Comparand, значение Exchange сохранится по адресу, указанному Destination. В противном случае операция не выполняется.

_InterlockedCompareExchange предоставляет встроенную поддержку компилятора для функции Win32 Windows SDK InterlockedCompareExchange.

Существуют несколько вариантов _InterlockedCompareExchange, они различаются в зависимости от типов данных, которые включают, и от того, используется ли семантика получения или освобождения конкретного процессора.

Функция _InterlockedCompareExchangeработает с длинными целыми значениями, _InterlockedCompareExchange8работает с 8-разрядными целыми значениями, _InterlockedCompareExchange16работает с короткими целыми значениями и _InterlockedCompareExchange64работает с 64-разрядными целыми значениями.

На платформах ARM используются встроенные функции с суффиксами _acq и _rel для получения и освобождения семантики, например, в начале и конце критической секции. Встроенные функции ARM с суффиксом _nf («без границ») не действуют как барьер памяти.

Встроенные функции с суффиксом _np («нет упреждающей выборки") запрещают возможную вставку компилятором операции упреждающей выборки.

На платформах Intel ®, поддерживающих инструкции Hardware Lock Elision (HLE), встроенные функции с суффиксами _HLEAcquire и _HLERelease включают подсказку процессору, как можно повысить производительность, устраняя шаг записи с блокировкой оборудования. Если эти встроенные функции вызываются на платформах, не поддерживающих HLE, подсказка игнорируется.

Эти процедуры доступны только как встроенные объекты.

Пример

В следующем примере _InterlockedCompareExchange используется для простой синхронизации потоков нижнего уровня. Такой подход имеет ограничения в качестве основы многопоточного программирования; он представлен, чтобы продемонстрировать типичное использование блокирующих встроенных функций. Для получения наилучших результатов используйте Windows API. Дополнительные сведения о многопоточном программировании см. написание многопоточной программы 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.
// Please 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;
}
  

См. также

Ссылки

_InterlockedCompareExchange128

Встроенные функции _InterlockedCompareExchangePointer

Встроенные объекты компилятора

Ключевые слова в C++

Конфликты с компилятором x86