一個良好的多線程庫,不應當一刀切的全加鎖。因為有些時候,雖然是多線程環境,但可能依照設計一個類隻會被一個線程操作,這個時候加鎖是多餘的,純浪費性能,但另一些場景又需要它是線程安全的。
假設有一個類X:
class X
{
public:
void xoo();
};
這裡總結幾個常見的做法:
1.本身不加鎖,由調用者來加鎖,壞處是如果多數場景都是加鎖的,由會産生重複代碼
class Z
void zoo()
{
LockHelper<CLock> lh(_lock); // 調用者Z來加鎖
_x.xoo();
};
private:
CLock _lock;
X _x;
2.類的實作中,加if判斷
X(bool is_threadsafe)
:_is_threadsafe(is_threadsafe)
}
void xoo()
if (_is_threadsafe)
{
// 根據條件加鎖
_lock.lock();
}
。。。。。。
_lock.unlock();
bool _is_threadsafe;
3.分成兩個類,第一個類是無鎖的,第二個類通過聚合第一個類,并用鎖包裝一下
class RawX
// RawX總是不加鎖
class SafeX
LockHelper<CLock> lh(_lock); // 總是加鎖
_raw_x.xoo();
RawX _raw_x;
下面提出一種在mooon中使用的相對更優雅的方法,引用一個空鎖類CNullLock,它僅提供鎖的接口,加鎖和解鎖函數體都是空的:
class CNullLock
void lock()
void unlock()
接下來看新的X的實作,需要将它變成一個模闆類:
template <class Lock>
LockHelper<CLock> lh(_lock); // 這裡并不一定真是加鎖
如果需要X是線程安全的,可以這樣使用:
X<CLock> x;
如果不需要X是線程安全的,則可以如下使用:
X<CNullLock> x;
這樣的一個X,看起來是不是相對優雅得體些了?