方法(1):
static SingletionClass* Instance()
{
Locker locker;
if (m_spInstance == NULL)
{
m_spInstance = new CShopMgrImpl;
}
return m_spInstance;
}
弊端:每次都需要锁,对性能有些影响
方法(2):
static SingletionClass* Instance()
{
if (m_spInstance == NULL)
{
Locker locker;
if (m_spInstance == NULL)
{
m_spInstance = new CShopMgrImpl;
}
}
return m_spInstance;
}
DCL(双重检测锁)实现,目前已经被证明是存在问题的。参考 "4.双重检查带来的问题"
方法(3):
static SingletionClass* Instance() {
static std::once_flag flag;
std::call_once(flag, [&] {
m_spInstance = new SingletionClass;
});
return m_spInstance;
}
使用c++11新特性,std::call_once 函数实现
问题:static std::once_flag flag 这个是静态变量,多线程访问不会有问题吗?
回答:不会,c++11已经保证静态变量初始化线程安全,参考"3.c++11对静态变量初始化线程安全的保证:"
方法(4):
static SingletionClass* getInstance(){ SingletionClass* sin= instance.load(std::memory_order_acquire); if ( !sin ){ std::lock_guard<std::mutex> myLock(myMutex); sin= instance.load(std::memory_order_relaxed); if( !sin ){ sin= new SingletionClass(); instance.store(sin,std::memory_order_release); } } // volatile int dummy{}; return sin; }
这个地方使用了内存栅栏技术,避免了双重检查锁带来的问题。
这个也是https://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf这篇论文中提到的使用内存栅栏的解决方法。
相关知识点书籍推荐:
《深入理解C++11:C++11新特性解析与应用》
https://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
1.类似的问题讨论以及参考:
https://spikez.tistory.com/349
https://www.modernescpp.com/index.php/thread-safe-initialization-of-a-singleton
2.内存栅栏:
https://preshing.com/20120710/memory-barriers-are-like-source-control-operations/
3.c++11对静态变量初始化线程安全的保证:
https://iamroman.org/blog/2017/04/cpp11-static-init/
https://stackoverflow.com/questions/1270927/are-function-static-variables-thread-safe-in-gcc
https://blog.csdn.net/imred/article/details/89069750
4.双重检查带来的问题:
https://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
c++11给出的解决方案:
https://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/
chrome给出的解决方案:
https://www.jianshu.com/p/3f6355cdd739
java的解决方案: