问题
在ACE
中大量使用锁策略作为模板参数,而它自适应两种策略的代价有多大呢?
分析
对于有锁场景,估计代价都差不多。而对于无锁场景,使用ACE
影响是几何呢?它还是高效的么?
ACE
经常在实现上使用锁策略作为模板参数,在模板方法实现中也经常使用ACE_MT (ACE_GUARD_* (...))
宏方法来实现对锁的使用。
特别地,ACE
提供了ACE_Guard
无锁的特化版本的ACE_Guard<ACE_Null_Mutex>
,以利于使用无锁策略时减少代价。
由于ACE_Guard<ACE_Null_Mutex>
大量使用内联方法,且返回值为恒定的常量,所以,在编译高度优化时,这些代码通常会被删减掉,进而,在运行时间是没有代价的,相当于没有加任何锁的代码!
学习:在此,需要崇拜下模板的元编程和编译器的伟力!
增强学习: 在某些类中不使用
虚函数,将会有内联上的方便
它山之石
**《Effective C++》**一书中说道,如果使用STL
应尽量了解<algorithm>
提供的各种算法,这些算法一般会比手写的排序、循环、或算法要快。
作者指出一个很重要的原因,就是STL
算法模板在编译器的加持下,与STL
各组件的充分内联,会比C qsort(...)
省去一些不必要的函数调用!
可见
C++
更适合大数量处理
兼谈模板与宏
我们知道,模板与宏都可以指导编译器生产代码,而且模板生产的代码,将会有更多的编译器检查,所以,应尽量用模板来替代宏!
但即使在ACE
中依然存在大量宏产生代码的场景,为何?
我想一个重要的原因就是,宏还是有其不可替代的优势!
例如,宏方法可以直接终止当前调用流程,见
ACE_GUARD_RETURN
宏方法。这点是模板方法,或模板类无法企及的特性,用模板反而带来代码上的累赘!用宏用的恰如其分 😃
参考
ACE_Guard宏方法
#if !defined (ACE_GUARD_ACTION)
#define ACE_GUARD_ACTION(MUTEX, OBJ, LOCK, ACTION, REACTION) \
ACE_Guard< MUTEX > OBJ (LOCK); \
if (OBJ.locked () != 0) { ACTION; } \
else { REACTION; }
#endif /* !ACE_GUARD_ACTION */
#if !defined (ACE_GUARD_REACTION)
#define ACE_GUARD_REACTION(MUTEX, OBJ, LOCK, REACTION) \
ACE_GUARD_ACTION(MUTEX, OBJ, LOCK, ;, REACTION)
#endif /* !ACE_GUARD_REACTION */
#if !defined (ACE_GUARD)
#define ACE_GUARD(MUTEX, OBJ, LOCK) \
ACE_GUARD_REACTION(MUTEX, OBJ, LOCK, return)
#endif /* !ACE_GUARD */
#if !defined (ACE_GUARD_RETURN)
#define ACE_GUARD_RETURN(MUTEX, OBJ, LOCK, RETURN) \
ACE_GUARD_REACTION(MUTEX, OBJ, LOCK, return RETURN)
#endif /* !ACE_GUARD_RETURN */
ACE_Guard特化无锁版本
template<>
class ACE_Export ACE_Guard<ACE_Null_Mutex>
{
public:
ACE_Guard (ACE_Null_Mutex &) {}
ACE_Guard (ACE_Null_Mutex &, int) {}
ACE_Guard (ACE_Null_Mutex &, int, int) {}
#if defined (ACE_WIN32)
~ACE_Guard () = default;
#endif /* ACE_WIN32 */
int acquire () { return 0; }
int tryacquire () { return 0; }
int release () { return 0; }
void disown () {}
int locked () { return 1; }
int remove () { return 0; }
void dump () const {}
private:
ACE_Guard (const ACE_Guard<ACE_Null_Mutex> &) = delete;
void operator= (const ACE_Guard<ACE_Null_Mutex> &) = delete;
ACE_Guard (ACE_Guard<ACE_Null_Mutex> &&) = delete;
void operator= (ACE_Guard<ACE_Null_Mutex> &&) = delete;
};