我对目的有点困惑std::call_once
。明确地说,我确切地理解什么std::call_once
does,以及如何使用它。它通常用于原子地初始化某种状态,并确保只有一个线程初始化该状态。我还在网上看到了许多尝试创建线程安全的单例std::call_once
.
As 在这里展示 http://www.nuonsoft.com/blog/2012/10/21/implementing-a-thread-safe-singleton-with-c11/comment-page-1/,假设您编写了一个线程安全的单例,如下所示:
CSingleton& CSingleton::GetInstance()
{
std::call_once(m_onceFlag, [] {
m_instance.reset(new CSingleton);
});
return *m_instance.get();
}
好吧,我明白了。但我以为唯一的事情std::call_once
真正保证的是传递的函数将only被执行一次。但有吗also保证如果多个线程之间存在调用该函数的竞争,并且一个线程获胜,则其他线程将获胜block直到获胜线程从调用返回?
因为如果是这样,我认为两者之间没有区别call_once
和一个普通的同步互斥体,例如:
CSingleton& CSingleton::GetInstance()
{
std::unique_lock<std::mutex> lock(m_mutex);
if (!m_instance)
{
m_instance.reset(new CSingleton);
}
lock.unlock();
return *m_instance;
}
So, if std::call_once
确实强制其他线程阻塞,那么有什么好处呢std::call_once
提供常规互斥锁吗?再想一想,std::call_once
肯定会have强制其他线程阻塞,或者用户提供的函数中完成的任何计算都不会同步。再说一遍,什么是std::call_once
提供高于普通互斥锁的价格吗?
一件事是call_once
为你做的是处理异常。也就是说,如果第一个线程在函子内部抛出异常(并将其传播出去),call_once
不会考虑call_once
使满意。允许后续调用再次进入函子,以努力完成它而不会出现异常。
在你的例子中,异常情况也得到了正确的处理。然而,很容易想象一个更复杂的函子,其中特殊情况将无法得到正确处理。
话虽这么说,我注意到call_once
与 function-local-statics 是多余的。例如。:
CSingleton& CSingleton::GetInstance()
{
static std::unique_ptr<CSingleton> m_instance(new CSingleton);
return *m_instance;
}
或者更简单地说:
CSingleton& CSingleton::GetInstance()
{
static CSingleton m_instance;
return m_instance;
}
上面相当于你的例子call_once
,恕我直言,更简单。哦,除了这个和你的例子之间的破坏顺序有非常微妙的不同。在这两种情况下m_instance
以与构建相反的顺序被破坏。但构建顺序不同。在你的m_instance
是相对于同一翻译单元中具有文件本地范围的其他对象构造的。使用函数局部静态,m_instance
是第一次构建GetInstance
被执行。
这种差异对于您的申请可能很重要,也可能不重要。一般来说,我更喜欢函数局部静态解决方案,因为它是“惰性的”。 IE。如果应用程序从不调用GetInstance()
then m_instance
从未被建造过。在应用程序启动期间,没有任何时期会尝试立即构建大量静态数据。您只需在实际使用时支付施工费用。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)