/*******************************************************************************
*	ファイル名：Atomic.h
*	用　　　途：アトミックアクセス関連定義
*	備　　　考：※Visual Studio2005以降 ＋ x86,x64プロセッサ専用
*				　上記以外のプラットホームでの使用は保証されません！
*	履　　　歴：
********************************************************************************/

/****************************
*	 コンパイル環境設定		*
****************************/
#pragma once

/****************************
*	インクルードファイル	*
****************************/
#include <intrin.h>

/****************************
*     定数・マクロ定義		*
****************************/

/// Interlocked...系API用アライメント宣言
#ifndef __ATOMIC_LONG_DEF__
#define __ATOMIC_LONG_DEF__
typedef	__declspec(align(32)) volatile long		ATOMIC_LONG ;
typedef	__declspec(align(64)) volatile void*	ATOMIC_PTR ;
#endif

/// アトミック操作マクロ
#define ATOMIC_TRYLOCK( value )			( InterlockedCompareExchange( &(value), 1, 0 ) == 0 )							// アトミックフラグのロックテスト
#define ATOMIC_LOCK( value )			while ( !ATOMIC_TRYLOCK(value) ) { ::Sleep(0) ; }								// アトミックフラグのロック
#define ATOMIC_UNLOCK( value )			( InterlockedCompareExchange( &(value), 0, 1 ) != 0 )							// アトミックフラグのロック解除
#define ATOMIC_TEST( value )			( InterlockedCompareExchange( &(value), 0, 0 ) != 0 )							// アトミックフラグのテスト
#define ATOMIC_SET( value )				( InterlockedExchange(&(value), 1) == 0 )										// アトミックフラグのセット
#define ATOMIC_RESET( value )			( InterlockedExchange(&(value), 0) != 0 )										// アトミックフラグのリセット
#define ATOMIC_SET_PTR( dst_p, src_p )	( InterlockedExchangePointer((void**)( &(dst_p) ), (void*)(src_p)) )			// アトミックポインタセット
#define ATOMIC_TEST_PTR( p )			( InterlockedCompareExchangePointer((void**)( &(p) ), NULL, NULL) != NULL )		// アトミックポインタのテスト
#define ATOMIC_GET_PTR( p )				  InterlockedCompareExchangePointer((void**)( &(p) ), NULL, NULL)				// アトミックポインタの取得
#define ATOMIC_INC( value )				  InterlockedIncrement( &(value) )												// アトミックポインタの取得
#define ATOMIC_DEC( value )				  InterlockedDecrement( &(value) )												// アトミックポインタの取得

/*******************************************************************************
*	ク ラ ス名：CAtomic32
*	用　　　途：アトミック整数クラス
*	備　　　考：スレッド間でアトミックに操作することが可能なクラス
*				但し、多様すると通常の処理より遅くなる
*				(代わりにクリティカルセクションを使用するかどうかは
*				 使用内容次第)
********************************************************************************/
class CAtomic32
{
//+-+---+---*---+---+---+---*---+---+---+---*---+---+---+---*---+---+---+---*---+---
public:
	/// 生成と消滅
							CAtomic32() ;
							CAtomic32( INT32 nVal ) ;
							CAtomic32( CAtomic32& rAnother ) ;
						   ~CAtomic32() ;

public:
	/// 各種操作メソッド
			void			Set( INT32 nVal ) ;						// A = n
			INT32			Get() ;									// n = A
			INT32			Add_Get( INT32 nVal ) ;					// ret = A + n
			INT32			Get_Add( INT32 nVal ) ;					// ret = A ; A += n
			INT32			Sub_Get( INT32 nVal ) ;					// ret = A - n
			INT32			Get_Sub( INT32 nVal ) ;					// ret = A ; a -= n
			INT32			Inc_Get() ;								// A++
			INT32			Get_Inc() ;								// ++A
			INT32			Dec_Get() ;								// A--
			INT32			Get_Dec() ;								// --A
			INT32			Get_Set( INT32 nVal ) ;					// ret = A ; A = n 
			INT32			Exchg( INT32 nVal ) ;					// ret = A ; A = n ;
			INT32			Comp_Exchg( INT32 nComp, INT32 nSet ) ;	// ret = ( A == C ) ? S : A
			BOOL			Test() ;								// ( A != 0 )

private:
	/// メンバー変数
			ATOMIC_LONG*	m_plVal ;								// 実体ポインタ
																	// 32bitアライメントされて
																	// いなければならない
} ;

