也许(......是的)解决了:在C ++上双重检查锁定:对临时指针的新内容,然后将其分配给实例

时间:2010-08-21 10:38:50

标签: c++ windows double-checked-locking

这是double checked locking上这篇文章的后续内容。我正在撰写一篇新帖子,因为似乎发布了一篇关于“老化”帖子的后续信息并不像发送新帖子一样可见/活跃,可能是因为大多数人都不按活动级别对stackoverflow中的帖子进行排序

对所有回复的人,感谢你在原帖中的所有意见。在咨询了Joe Duffy的优秀书籍"Concurrent Programming on Windows"后,我现在认为我应该使用下面的代码。除了一些变量重命名和InterlockedXXX系列之外,它与他书中的代码基本相同。以下实现使用:

    temp和“actual”指针上的
  1. volatile 关键字,以防止从编译器重新排序。
  2. InterlockedCompareExchangePointer 以防止重新排序 CPU
  3. 那么,这应该是非常安全的(......对吗?):

    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_;
    };
    

1 个答案:

答案 0 :(得分:2)

我总是使用更简单的单例模式。

class CSomething
{
protected:
    CSomething() {};
public:
    ~CSomething() {};
    static CSomething *Get()
    {
        static CSomething s;
        return &s;
    }
    // Rest of the class
};