13

スレッドセーフな二重チェック ロック (シングルトンまたは遅延初期化の場合) に関する多くの質問を読みました。一部のスレッドでは、答えはパターンが完全に壊れているというものであり、他のスレッドでは解決策を提案しています。

だから私の質問は: C++ で完全にスレッド セーフな二重チェック ロック パターンを記述する方法はありますか? もしそうなら、それはどのように見えますか。

それが物事をより簡単にするならば、C++11を仮定することができます。私の知る限り、C++11 はメモリ モデルを改善し、必要な改善をもたらすことができました。

ダブルチェックで保護された変数を揮発性にすることで、Javaでそれが可能であることを私は知っています。C++11 はメモリ モデルの大部分を Java のものから借りてきたので、それは可能だと思いますが、どうすればよいでしょうか?

4

2 に答える 2

18

次のように、遅延初期化されたシングルトンに静的ローカル変数を使用するだけです。

MySingleton* GetInstance() {
  static MySingleton instance;
  return &instance; 
}

(C++11) 標準では、静的変数がスレッドセーフな方法で初期化されることが既に保証されており、この実装は、少なくとも自分で作成するものと同じくらい堅牢でパフォーマンスが高いようです。

初期化のスレッドセーフは、(C++11) 標準の §6.7.4 にあります。

変数の初期化中に制御が同時に宣言に入った場合、同時実行は初期化の完了を待ちます。

于 2012-09-06T14:28:03.290 に答える
3

有効な DCLP C++11 実装を確認したかったので、ここに 1 つを示します。

GetInstance()動作は完全にスレッドセーフであり、グリズリーの回答と同じです。

std::mutex mtx;
std::atomic<MySingleton *> instance_p{nullptr};

MySingleton* GetInstance()
{
    auto *p = instance_p.load(std::memory_order_acquire);

    if (!p)
    {
        std::lock_guard<std::mutex> lck{mtx};

        p = instance_p.load(std::memory_order_relaxed);
        if (!p)
        {
            p = new MySingleton;
            instance_p.store(p, std::memory_order_release);
        }
    }

    return p;
}
于 2017-08-19T04:09:11.360 に答える