这是double checked locking上这篇文章的后续内容。我正在撰写一篇新帖子,因为似乎发布了一篇关于“老化”帖子的后续信息并不像发送新帖子一样可见/活跃,可能是因为大多数人都不按活动级别对stackoverflow中的帖子进行排序
对所有回复的人,感谢你在原帖中的所有意见。在咨询了Joe Duffy的优秀书籍"Concurrent Programming on Windows"后,我现在认为我应该使用下面的代码。除了一些变量重命名和InterlockedXXX系列之外,它与他书中的代码基本相同。以下实现使用:
那么,这应该是非常安全的(......对吗?):
template <typename T>
class LazyInit {
public:
typedef T* (*Factory)();
LazyInit(Factory f = 0)
: factory_(f)
, singleton_(0)
{
::InitializeCriticalSection(&cs_);
}
T& get() {
if (!singleton_) {
::EnterCriticalSection(&cs_);
if (!singleton_) {
T* volatile p = factory_();
// Joe uses _WriterBarrier(); then singleton_ = p;
// But I thought better to make singleton_ = p atomic (as I understand,
// on Windows, pointer assignments are atomic ONLY if they are aligned)
// In addition, the MSDN docs say that InterlockedCompareExchangePointer
// sets up a full memory barrier.
::InterlockedCompareExchangePointer((PVOID volatile*)&singleton_, p, 0);
}
::LeaveCriticalSection(&cs_);
}
#if PREVENT_IA64_FROM_REORDERING
_ReadBarrier();
#endif
return *singleton_;
}
virtual ~LazyInit() {
::DeleteCriticalSection(&cs_);
}
private:
CRITICAL_SECTION cs_;
Factory factory_;
T* volatile singleton_;
};
答案 0 :(得分:2)
我总是使用更简单的单例模式。
class CSomething
{
protected:
CSomething() {};
public:
~CSomething() {};
static CSomething *Get()
{
static CSomething s;
return &s;
}
// Rest of the class
};