在软件开发中,我们经常会遇到多个线程对同一数据操作的同步问题,如果需要同步保护的是一组变量,则直接分用互斥锁进行保护,可以如果需要保护的只是一个整数(如:int,long...),则有更为高效的办法:ACE_Atomic_Op
ACE_Atomic_Op<class ACE_LOCK, class TYPE>是ACE提高的一个对不同平台上对象原子操作的一个包装类。这个类能过重写各种操作符(+=,++,--,=...)的实现,提供了对对象(由TYPE参数确定)的所有常见操作(+=,++,--,=...)的多线程保护!
由于我当前的需求,我要重点关注的是这个模板类的两个特化实现!
ACE_Atomic_Op<ACE_Thread_Mutex, long>
ACE_Atomic_Op<ACE_Thread_Mutex, unsigned long>
这两个特化实现,针对整数的操作进行了特别的优化,它根据所在的 平台 及 CPU 的个数来选择最高效的方法,使对单个整数的读写保护不需要使用互斥锁就可完成, 效率有了极大的提高。
让我们来看一下它的源代码:
1. 初始化
在ACE::init调用时,会能过调用ACE_Atomic_Op::init_functions函数,初始化相关的原子操作函数:
void
ACE_Atomic_Op<ACE_Thread_Mutex, unsigned long>::init_functions (void)
{
if (ACE_OS::num_processors () == 1)
{ //当前系统只有单个CPU
increment_fn_ = single_cpu_increment;
decrement_fn_ = single_cpu_decrement;
exchange_fn_ = single_cpu_exchange;
exchange_add_fn_ = single_cpu_exchange_add;
}
else
{//当前系统有多个CPU
increment_fn_ = multi_cpu_increment;
decrement_fn_ = multi_cpu_decrement;
exchange_fn_ = multi_cpu_exchange;
exchange_add_fn_ = multi_cpu_exchange_add;
}
}
2. 具体操作:
ACE_Atomic_Op支持对整数的加减等常见操作,以我们++操作为例:
ACE_INLINE unsigned long
ACE_Atomic_Op<ACE_Thread_Mutex, unsigned long>::operator++ (void)
{
#if defined (WIN32)
return static_cast<unsigned long> (::InterlockedIncrement (const_cast<long *> (reinterpret_cast<volatile long *>(&this->value_))));
#else /* WIN32 */
return static_cast<unsigned long> ((*increment_fn_) (reinterpret_cast<volatile long *> (&this->value_)));
#endif /* WIN32 */
}
当在Win32平台时会调用windows提供的原子加操作API,再在其平台上,会调用在初始化时所指确定的原子加操作函数,这些函数其基上都是使用各平台提供相关汇编指令实现的。所有这些操作不用加锁就可完成原子操作,效率非常高!
以下为单CPU上加的原子操作函数实现代码:
long
single_cpu_exchange_add (volatile long *value, long rhs)
{
#if defined (ACE_HAS_INTEL_ASSEMBLY)
unsigned long addr = reinterpret_cast<unsigned long> (value);
asm( "xadd %0, (%1)" : "+r"(rhs) : "r"(addr) );
return rhs;
#elif defined (sun) || \
(defined (__SUNPRO_CC) && (defined (__i386) || defined (__x86_64)))
return ace_atomic_swap_add_long (
reinterpret_cast<volatile unsigned long*> (value), rhs);
#elif defined(__GNUC__) && defined(PPC)
long tmp;
asm("add %0,%1,%2" : "=r" (tmp) : "r" (*value), "r" (rhs) );
asm("stw %0,%1" : "+r" (tmp), "=m" (*value) );
return tmp;
#elif defined (WIN32) && !defined (ACE_HAS_INTERLOCKED_EXCHANGEADD)
# if defined (_MSC_VER)
__asm
{
mov eax, rhs
mov edx, value
xadd [edx], eax
}
// Return value is already in EAX register.
# elif defined (__BORLANDC__)
_EAX = rhs;
_EDX = reinterpret_cast<unsigned long> (value);
__emit__(0x0F, 0xC1, 0x02); // xadd [edx], eax
// Return value is already in EAX register.
# else /* _MSC_VER */
ACE_UNUSED_ARG (value);
ACE_UNUSED_ARG (rhs);
ACE_NOTSUP_RETURN (-1);
# endif /* _MSC_VER */
#else /* ACE_HAS_INTEL_ASSEMBLY*/
ACE_UNUSED_ARG (value);
ACE_UNUSED_ARG (rhs);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_INTEL_ASSEMBLY*/
}
ACE_Atomic_Op<class ACE_LOCK, class TYPE>是ACE提高的一个对不同平台上对象原子操作的一个包装类。这个类能过重写各种操作符(+=,++,--,=...)的实现,提供了对对象(由TYPE参数确定)的所有常见操作(+=,++,--,=...)的多线程保护!
由于我当前的需求,我要重点关注的是这个模板类的两个特化实现!
ACE_Atomic_Op<ACE_Thread_Mutex, long>
ACE_Atomic_Op<ACE_Thread_Mutex, unsigned long>
这两个特化实现,针对整数的操作进行了特别的优化,它根据所在的 平台 及 CPU 的个数来选择最高效的方法,使对单个整数的读写保护不需要使用互斥锁就可完成, 效率有了极大的提高。
让我们来看一下它的源代码:
1. 初始化
在ACE::init调用时,会能过调用ACE_Atomic_Op::init_functions函数,初始化相关的原子操作函数:
void
ACE_Atomic_Op<ACE_Thread_Mutex, unsigned long>::init_functions (void)
{
if (ACE_OS::num_processors () == 1)
{ //当前系统只有单个CPU
increment_fn_ = single_cpu_increment;
decrement_fn_ = single_cpu_decrement;
exchange_fn_ = single_cpu_exchange;
exchange_add_fn_ = single_cpu_exchange_add;
}
else
{//当前系统有多个CPU
increment_fn_ = multi_cpu_increment;
decrement_fn_ = multi_cpu_decrement;
exchange_fn_ = multi_cpu_exchange;
exchange_add_fn_ = multi_cpu_exchange_add;
}
}
2. 具体操作:
ACE_Atomic_Op支持对整数的加减等常见操作,以我们++操作为例:
ACE_INLINE unsigned long
ACE_Atomic_Op<ACE_Thread_Mutex, unsigned long>::operator++ (void)
{
#if defined (WIN32)
return static_cast<unsigned long> (::InterlockedIncrement (const_cast<long *> (reinterpret_cast<volatile long *>(&this->value_))));
#else /* WIN32 */
return static_cast<unsigned long> ((*increment_fn_) (reinterpret_cast<volatile long *> (&this->value_)));
#endif /* WIN32 */
}
当在Win32平台时会调用windows提供的原子加操作API,再在其平台上,会调用在初始化时所指确定的原子加操作函数,这些函数其基上都是使用各平台提供相关汇编指令实现的。所有这些操作不用加锁就可完成原子操作,效率非常高!
以下为单CPU上加的原子操作函数实现代码:
long
single_cpu_exchange_add (volatile long *value, long rhs)
{
#if defined (ACE_HAS_INTEL_ASSEMBLY)
unsigned long addr = reinterpret_cast<unsigned long> (value);
asm( "xadd %0, (%1)" : "+r"(rhs) : "r"(addr) );
return rhs;
#elif defined (sun) || \
(defined (__SUNPRO_CC) && (defined (__i386) || defined (__x86_64)))
return ace_atomic_swap_add_long (
reinterpret_cast<volatile unsigned long*> (value), rhs);
#elif defined(__GNUC__) && defined(PPC)
long tmp;
asm("add %0,%1,%2" : "=r" (tmp) : "r" (*value), "r" (rhs) );
asm("stw %0,%1" : "+r" (tmp), "=m" (*value) );
return tmp;
#elif defined (WIN32) && !defined (ACE_HAS_INTERLOCKED_EXCHANGEADD)
# if defined (_MSC_VER)
__asm
{
mov eax, rhs
mov edx, value
xadd [edx], eax
}
// Return value is already in EAX register.
# elif defined (__BORLANDC__)
_EAX = rhs;
_EDX = reinterpret_cast<unsigned long> (value);
__emit__(0x0F, 0xC1, 0x02); // xadd [edx], eax
// Return value is already in EAX register.
# else /* _MSC_VER */
ACE_UNUSED_ARG (value);
ACE_UNUSED_ARG (rhs);
ACE_NOTSUP_RETURN (-1);
# endif /* _MSC_VER */
#else /* ACE_HAS_INTEL_ASSEMBLY*/
ACE_UNUSED_ARG (value);
ACE_UNUSED_ARG (rhs);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_INTEL_ASSEMBLY*/
}