Windows の Interlocked 系 API は atomic な操作に使われます。
例えば InterlockedIncrement() は load と store を含みますが、その間に他の
スレッドが同じメモリを書き換えることなく処理が完了するよう調整されます。
x64 でコンパイルするとこれらの Interlocked API はインライン展開されるようです。
下記のように同機能の intrinsic 命令が用意されおり、x64 では単なる別名として
定義されていました。
・InterlockedCompareExchange Function
・_InterlockedCompareExchange Intrinsic Functions
x86 でも直接 _InterlockedCompareExchange() を使えば組み込み命令として機能します。
実際のコードは下記の通り。
x64: lock cmpxchg dword ptr [mem32],edx // InterlockedCompareExchange lock cmpxchg qword ptr [mem64],rdx // InterlockedCompareExchange64 x86: lock cmpxchg dword ptr [mem32],edx // InterlockedCompareExchange lock cmpxchg8b qword ptr [mem64] // InterlockedCompareExchange64
InterlockedIncrement() + x64 の場合
// 返値参照あり mov ecx,1 lock xadd dword ptr [mem],ecx inc ecx // 返値参照無し lock add dword ptr [mem],1
返値を参照するかどうかによって、命令そのものも置き換わっています。
単なる関数や asm 文の inline ではなく、組み込み命令であることがよくわかります。
以前紹介した Gamefest2008 のスライドによると DirectX11 の Compute Shader
には下記の命令が追加されるようです。
InterlockedAdd()
InterlockedMin()
InterlockedMax()
InterlockedOr()
InterlockedXor()
InterlockedCompareWrite()
InterlockedCompareExchange()
・Gamefest 2008 Presentations
「Direct3D 11 Computer Shader More Generality for Advanced Techniques」
InterlockedMin()/InterlockedMax() は Win32 API に無い命令です。
書いてみるとこんな感じでしょうか。(厳密な動作は未検証)
templatevoid InterlockedMin( T volatile* mem, T val ) { union { T fval; long ival; } cur; do{ cur.fval= *mem; if( cur.fval <= val ){ break; } }while( _InterlockedCompareExchange( reinterpret_cast ( mem ), *reinterpret_cast ( &val ), cur.ival ) != cur.ival ); }
関連エントリ
・Direct3D11 Compute Shader など
・SSE3 の monitor mwait 命令