-1

これは、二重チェック ロックに関するこの投稿のフォローアップです。「古い」投稿にフォローアップを投稿しても、新しい投稿を送信するほど表示/アクティブにならないように思われるため、新しい投稿を書いています。おそらく、ほとんどの人がスタックオーバーフローの投稿をアクティビティのレベルで並べ替えていないためです。 .

回答者の皆様、元の投稿へのご意見ありがとうございます。Joe Duffy の優れた「Concurrent Programming on Windows」を参照した後、以下のコードを使用する必要があると考えています。一部の変数の名前変更と InterlockedXXX 行を除いて、これは彼の本のコードとほとんど同じです。次の実装では以下を使用します。

  1. 一時ポインターと「実際の」ポインターの両方にvolatileキーワードを追加して、コンパイラーからの並べ替えから保護します。
  2. CPUからの並べ替えから保護するためのInterlockedCompareExchangePointer

だから、それはかなり安全なはずです(...そうですか?):

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

1 に答える 1

2

私はずっと単純なシングルトン パターンを使用してきました。

class CSomething
{
protected:
    CSomething() {};
public:
    ~CSomething() {};
    static CSomething *Get()
    {
        static CSomething s;
        return &s;
    }
    // Rest of the class
};
于 2010-08-22T11:42:06.357 に答える