InterlockedCompareExchange是把目標運算元(第1參數所指向的記憶體中的數)與一個值(第3參數)比較,如果相等,則用另一個值(第2參數)與目標運算元(第1參數所指向的記憶體中的數)交換;InterlockedExchange是不比較直接交換。
函式功能,增減,交換,比較交換,參數,返回值,備註,示例,
函式功能
整個操作過程是鎖定記憶體的,其它處理器不會同時訪問記憶體,從而實現多處理器環境下的執行緒互斥。
InterlockedCompareExchange屬於Interlocked系列互鎖函式之一,常用於多執行緒編程。類似的還有下面的幾個:
增減
(1) LONG InterlockedIncrement(IN OUT LONG volatile *lpAddend);
(2) LONG InterlockedDecrement(IN OUT LONG volatile *lpAddend);
lpAddend為長整型變數的地址,返回值為原始值。這個函式的主要作用是原子性自減(相當於--操作)。
(3) LONG InterlockedExchangeAdd( LPLONG Addend, LONG Increment );
Addend為長整型變數的地址,Increment為想要在Addend指向的長整型變數上增加的數值(可以是負數)。這個函式的主要作用是保證這個加操作為一個原子訪問。
交換
(1) LONG InterlockedExchange( LPLONG Target, LONG Value );
(2) PVOID InterlockedExchangePointer( PVOID *Target, PVOID Value );
用第二個參數的值取代第一個參數指向的值。函式返回值為原始值。
比較交換
(1) LONG InterlockedCompareExchange(
LPLONG Destination, LONG Exchange, LONG Comperand );
(2) PVOID InterlockedCompareExchangePointer(
PVOID *Destination, PVOID Exchange, PVOID Comperand );
如果第三個參數與第一個參數指向的值相同,那么用第二個參數取代第一個參數指向的值。函式返回值為原始值。
參數
[in, out] Destination
對目標指針的值。 該符號被忽略。
[in] Exchange 交換值。 該符號被忽略。
[in] ExchangeHigh 目標的高部分交換值。
[in] ExchangeLow 目標的下半部分交換值。
[in] Comparand 比較的值與目標。 該符號被忽略。
返回值
返回值是 Destination 指針的初始值。
備註
請注意,生成內部展開,需要使用 /Oi。 /Oi 提示與 /O2。
若要聲明一個互鎖的函式用作內部,必須聲明函式使用反斜前導下劃線,並且新的函式必須出現在 #pragma 內部 語句。 為了方便起見,函式的內部版本。 #define 語句中聲明出現在原始碼,而無需這個前導下劃線。
_InterlockedCompareExchange 執行 Destination 值的基本比較與 Comparand 值。 如果 Destination 值與 Comparand 值相等, Exchange值。 Destination指定的地址存儲。 否則,不執行操作。
有關此示例演示如何使用 _InterlockedCompareExchange,請參見 InterlockedDecrement。
具有根據數據類型所涉及在 _InterlockedCompareExchange 的多種變體,並處理器特定是否可捕獲或使用語義版本。
當 _InterlockedCompareExchange 函式對長整數值時, _InterlockedCompareExchange16 對短整型值,並_InterlockedCompareExchange64 對 64 位整數值。 由於 _InterlockedCompareExchange64 使用 cmpxchg8b 命令,則不能在之前 Pentium 處理器,如 486。
IPF 特定 _InterlockedCompareExchange_acq、 _InterlockedCompareExchange16_acq和 _InterlockedCompareExchange64_acq 內部函式是不 acq 後綴,但操作的相應功能執行獲取語義,很有用,在輸入臨界區時的行為相同。
_InterlockedCompareExchange_rel、 _InterlockedCompareExchange16_rel和 _InterlockedCompareExchange64_rel 內部函式是不rel 後綴,但操作的相應函式執行與版本語義,很有用,在離開臨界區時的行為相同。
這些功能的行為就如同讀寫記憶體屏障 有關更多信息,請參見 ReadWriteBarrier。
這些實例只能用作內部。
示例
在下面的示例中, _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!
// call __yield() here on the IPF architecture to improve
// performance.
}
// This will also work.
//while (_InterlockedExchange(pl, LOCK_IS_TAKEN) ==
// LOCK_IS_TAKEN)
//{
// // spin!
//}
// At this point, the lock is acquired.
}
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(
)
{
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
AMP_LT1
AMP_LT2
AMP_LT3
AMP_LT4
AMP_LT5
AMP_LT6
AMP_LT7
AMP_LT8
AMP_LT9
AMP_LT10
AMP_LT11
AMP_LT12
AMP_LT13
AMP_LT14
AMP_LT15
AMP_LT16
AMP_LT17
AMP_LT18
AMP_LT19
AMP_LT20
AMP_LT21
AMP_LT22
AMP_LT23
AMP_LT24
AMP_LT25
AMP_LT26
AMP_LT27
AMP_LT28
AMP_LT29