2016-09-12 25 views
1

this C++のDouble Checked Locking Patternについての記事は、volatileを使用してDCLPを正しく実装する方法の1つを示しています変数:C++でDouble Checked Lockingを実装するには

class Singleton { 
public: 
    static volatile Singleton* volatile instance(); 

private: 
    static volatile Singleton* volatile pInstance; 
}; 

// from the implementation file 
volatile Singleton* volatile Singleton::pInstance = 0; 
volatile Singleton* volatile Singleton::instance() { 
    if (pInstance == 0) { 
    Lock lock; 
    if (pInstance == 0) { 
     volatile Singleton* volatile temp = new Singleton; 
     pInstance = temp; 
    } 
    } 
    return pInstance; 
} 

私は理解していないテキストの抜粋があり、このような例の後:

まず、観察可能な行動上の標準の制約は唯一 のために駅で定義された抽象マシンですその抽象マシン には複数の実行スレッドの概念がありません。 標準並べ替えからコンパイラを防ぎも読み取り、 揮発性データ内スレッドへの書き込み結果として、それは 例えばreorderings 横切るスレッドに全く制約を課しません。少なくとも、それはほとんどのコンパイラ の実装者が物を解釈する方法です。その結果、実際には、多くの コンパイラが上記のソースからスレッドに安全でないコードを生成する可能性があります。

以降:

... C++の抽象機械はシングルスレッドであり、そしてC++コンパイラは とにかく 、上記のようなソースからスレッド安全でないコードを生成することを選択してもよいです。

これらの注釈は、ユニプロセッサでの実行に関連しているため、キャッシュの一貫性に関する問題ではありません。

コンパイラが順序変更することができない場合スレッド揮発性データへの読み込みと書き込み、それがどのように並べ替えることができますので、スレッドセーフでないコードを生成し、この特定の例のために全体でスレッドを読み込みと書き込み?

volatile Singleton* volatile temp = new Singleton; 
pInstance = temp; 

中に、::

+0

この記事は2004年のものであり、C++ 11とそれを更新した抽象的なマシンよりもかなり前の年です。 – molbdnilo

+0

@molbdniloしかし、コンパイラが_across_スレッドの読み書きをどのように並べ替えることができますか? – undermind

答えて

0

私は、彼らがシングルスレッド抽象機械の文脈で、コンパイラは、単に変換することができると言っている正しく理解していた場合

pInstance = new Singleton; 

観察可能な行動ので、変わらない。それで、これは二重チェックされたロックで元の問題に戻ります。

+0

しかし、私は、 'volatile'を使うと逆に、コンパイラがあなたが言及した最適化を行わないようにすると考えました。 C++ 03 Standard 1.9.6によれば、「抽象機械の観察可能な動作は、揮発性データへの読み書きとライブラリI/O機能への呼び出し」であり、1.9.7:「 a 'volatile'の値は、オブジェクトを変更しています...すべての副作用です...特定の時点で 指定されたポイント...前の評価の副作用はすべて完了し、その後の評価の副作用は起こらないものとします。 – undermind

1

私は値がある前に、マルチプロセッサシステムでは、プロセッサ/キャッシュハードウェアがpInstanceの値を書き込むことができる。彼らはセクション6(「マルチプロセッサマシン上DCLP」で説明キャッシュ・コヒーレンシの問題に言及していると思います

これは、他のCPUより前にすべてのメモリが更新されていることを確認するためのハードウェアフェンス命令を必要とします。これは、割り当てられたSingletonに対して書き出されます。システム内のいずれかを見ることができます。

+0

セクション5の最後に発言しているため、マルチプロセッサ実行するとさらに多くの問題が発生する可能性がありますが、セクション6はマルチプロセッサマシン_DCLPの明示的な名前であり、セクション1_Inroduction_では「この記事では、 DCLPは、ユニプロセッサーとマルチプロセッサーの両方の**アーキテクチャーで失敗する可能性があり、なぜそれについて何もできないのです。 " – undermind

1

リートンは揮発性かもしれないが、データ以内にシングルトンはありません。

シングルトンは何らかの理由でコンストラクタ内で15, 16, 17に設定され、メンバとしてint x, y, z;をメンバーとして持つと想像してください。

volatile Singleton* volatile temp = new Singleton; 
    pInstance = temp; 

OK、temppInstance前に書かれています。これらに対して、x,y,zの書面はいつですか?前?後?あなたは知らない。それらは揮発性ではないため、揮発性の順序に関連して発注する必要はありません。

今のスレッドがでてくると見ている:

if (pInstance == 0) { // first check 

とのはpInstanceが設定されているとしましょう、nullではありません。 x,y,zの値は何ですか? new Singletonが呼び出されていて、コンストラクターに「実行」がある場合でも、x,y,zを設定した操作が実行されたかどうかはわかりません。

コードがx,y,zになり、クラッシュしました。実際にはランダムなデータではなく、15,16,17が予想されていました。

ああ待って、pInstanceは揮発性データへの揮発性のポインタです!だからx,y,zは揮発性ですか?右?そして、pInstancetempで注文しました。ああ!

ほぼ。 *pInstanceからの読み取りはすべて揮発性ですが、new Singletonによる構築は揮発性ではありません。したがって、x,y,zへの最初の書き込みは発注されませんでした。 :-(

ですから多分は、メンバーvolatile int x, y, z;はOK作ることができます。しかし...今

C++ は記事だったとき、それはしなかった場合でも、メモリモデルを持っています書かれた。現在のルールの下では、volatileは、データ競合を防ぐことはできません。volatileスレッドとは何の関係もありません。プログラムはUBである。猫と犬が一緒に住んでいる。また

を、これは標準の限界に挑戦ですが(つまり、それは012と曖昧になる完全にプログラムを最適化しているコンパイラは、volatileの用途を見て、「いいえ、これらの揮発性物質は実際にはIOメモリアドレスなどには接続しません。私はそれらを不揮発性にするつもりです。 "...

+0

申し訳ありませんが、実際には私が言及している記事の一部を省略しました(私は疑問を明確にすると信じていました)その部分では、あなたが記述している問題に対処しています。コンストラクタ内のシングルトンのフィールドの初期化は、 'static_cast (x)= 5;'しかし、この後も、そのような解決策はスレッドセーフではないコードの生成に関する問題を解決しないと主張している。私は現代のC++に精巧なメモリモデルがあることを知っていますが、作者の意味は面白かったです。 – undermind

+0

OK、私は今(再)記事を読んでいる(それは数年経っている)。私はあなたが引用しているビットと、次のセクションにつながるセクションの終わりが実際に大きな重みを持っていないと言いたいと思う。 (また、たとえば、すべての共通アーキテクチャ(つまりすべての共通アーキテクチャー)がキャッシュ・コヒーレンシを保証しているため、キャッシュ・コヒーレンシはマルチプロセッサの問題ではありません)、問題は読み取り/書き込みバッファーにあります。記事はありますが、必ずしも完璧ではありません。)とにかく、巨大な+ユニプロセッサーは実際にスレッドセーフであるかもしれません。しかし、「不安定」はあまり定義されていないので、私はそれに数えません。 – tony

関連する問題