如果你的系统有读写锁,恭喜你,也许你可以比较方便的解决这个问题。你可以这么写:
// Singleton.h
class Singleton
{
public:
~Singleton(){}
static Singleton& getInstance();
private:
Singleton(){}
static RWLock rwlock_;
};
// Singleton.cpp
/* static */
Lock Singleton::lock_;
Singleton& Singleton::getInstance()
{
static Singleton *instance = NULL;
rwlock.rdlock();
if (NULL == instance) // thread B Pos1
{
rwlock.unlock();
{
WLockGuard wguard(rwlock);
if (NULL == instance)
{
instance = new Singleton; // thread A Pos2
}
return instance;
}
}
rwlock.unlock();
return &instance;
}
这段代码没有符合一个return的原则,之所以这么写是因为singleton的构造函数有可能会有异常,那么这么封装,可以最大程度的保证不会死锁。这段代码比上一段已经有很大程度的改变了。首先,当instance初始化之后,以后就全部是读锁了,只有一个简单函数的开销(相对被mutex锁住切换context的开销,一个函数的调用要小多了,这个函数不是指rwlock.rdlock(),因为这个函数本身100%是inline的;而是指pthread_rwlock_rdlock这样的函数调用)。但是大家也许已经发现了,如果在很多线程同时初始化这个instance的时候,还是会有等待锁的情况发生。那有没有办法解决这个问题呢?答案是可以的,不过需要用到一些同步原语,包括Atomic和Memory Barrier。我不会再写去了,因为我觉得这些高级的功能,我们一定要抵制这种诱惑。因为如果用这些你的代码会有以下两个缺点:
(1)可读性较差
(2)移植性较差(你可以写很多宏来帮助你在不同平台不同CPU上使用,譬如Chrome)
如果你有兴趣,请察看chrome的源代码的Base/singleton的实现。