_InterlockedCompareExchange の組み込み関数
[このドキュメントはプレビュー版であり、後のリリースで変更されることがあります。 Blank topics are included as placeholders.]
Microsoft 固有の仕様 →
Win32 Windows SDK InterlockedCompareExchange の関数にはコンパイラの組み込みサポートが用意されています。
long _InterlockedCompareExchange(
long volatile * Destination,
long Exchange,
long Comparand
);
long _InterlockedCompareExchange_acq(
long volatile * Destination,
long Exchange,
long Comparand
);
long _InterlockedCompareExchange_rel(
long volatile * Destination,
long Exchange,
long Comparand
);
short _InterlockedCompareExchange16(
short volatile * Destination,
short Exchange,
short Comparand
);
short _InterlockedCompareExchange16_acq(
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_rel(
__int64 volatile * Destination,
__int64 Exchange,
__int64 Comparand
);
unsigned char _InterlockedCompareExchange128(
__int64 volatile * Destination,
__int64 ExchangeHigh,
__int64 ExchangeLow,
__int64 * Comparand
);
パラメーター
[入力、出力] Destination
終了値へのポインター。 記号は無視されます。[入力] Exchange
交換する必要があります。 記号は無視されます。[入力] ExchangeHigh
コピー先の高い部分の交換値。[入力] ExchangeLow
コピー先の下位部分の交換値。[入力] Comparand
ターゲットと比較する値。 記号は無視されます。
戻り値
戻り値は Destination の初期値です。
必要条件
組み込み |
アーキテクチャ |
---|---|
_InterlockedCompareExchange |
x86IPFx64 |
_InterlockedCompareExchange_acq |
IPF |
_InterlockedCompareExchange_rel |
IPF |
_InterlockedCompareExchange16 |
x86IPFx64 |
_InterlockedCompareExchange16_acq |
IPF |
_InterlockedCompareExchange16_rel |
IPF |
_InterlockedCompareExchange64 |
Pentium x86IPF () *x64 |
_InterlockedCompareExchange64_acq |
IPF |
_InterlockedCompareExchange64_rel |
IPF |
_InterlockedCompareExchange128 |
x64 |
メモ : _InterlockedCompareExchange64 はPentium x86 アーキテクチャで実行するシステムに含まれています ; ここでは386 または 486 のアーキテクチャでは使用できません。
ヘッダー ファイル <intrin.h>
解説
組み込みの配置生成するには/Oi を使用する必要があることに注意してください。 /Oi は /O2 と暗黙的に指定されます。
組み込みとして使用するためにインタロック関数の 1 種類を宣言するには先頭にアンダースコア () として宣言されて新しい関数は #pragma 組み込み のステートメントで使用する必要があります。 便宜上関数の基本的なバージョンでは #define のステートメントの先頭にアンダースコア () を使用せずにソース・コードに表示されるように宣言できます。
_InterlockedCompareExchange は Comparand の値と Destination の値をアトミックに比較を実行します。 Destination の値が Comparand の値と等しい場合Exchange の値は Destination で指定したアドレスに格納されます。 それ以外の場合は、操作が実行されません。
_InterlockedCompareExchange を使用する方法の例については _InterlockedDecrement を参照してください。
リリースではセマンティクス使用することが含まれるかおよびプロセッサ固有または取得したりデータ型に基づいて異なる _InterlockedCompareExchange にいくつかのバリエーションがあります。
_InterlockedCompareExchange の関数が長整数値を操作しますが**_InterlockedCompareExchange16** は短整数値を操作し**_InterlockedCompareExchange64** は64 ビットの整数値を操作します。 _InterlockedCompareExchange64 が cmpxchg8b 命令を使用するため486 などの以前 Pentium プロセッサでは使用できません。
IPF 固有 _InterlockedCompareExchange_acq_InterlockedCompareExchange16_acq と _InterlockedCompareExchange64_acq の組み込み関数は acq のサフィックスが操作の対応する関数が取得したりのセマンティクスを場合と同じです。クリティカル セクションに入るとき。
_InterlockedCompareExchange_rel _InterlockedCompareExchange16_rel と _InterlockedCompareExchange64_rel の組み込み関数は rel のサフィックスが操作の対応する関数を使用すると便利リリースのセマンティクスは同じです。クリティカル セクションを離れる場合。
これらの関数は読み書き可能メモリ バリアとして機能します。 詳細については_ReadWriteBarrier を参照してください。
これらのルーチンは組み込みとしてのみ使用できます。
使用例
次の例では**_InterlockedCompareExchange** は単純な低レベルのスレッドの同期に使用されます。 アプローチにマルチスレッド プログラミングの基礎として制限されています ; Interlocked 組み込みの一般的な使用法を示すことを示します。 最適な結果を得るために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.
#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;
}
参照
Reference
_InterlockedCompareExchange128
_InterlockedCompareExchangePointer の組み込み関数