問題タブ [double-checked-locking]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
java - Singleton クラスの場合、このように二重チェックのロックが失敗しないのはなぜですか?
この構造が壊れていると見なされる理由は、一般に、ヘルパー変数への書き込み後にヘルパー コンストラクターが呼び出されるように、コンパイラによって行われる割り当ての並べ替えが説明されています。私の質問は、このコードがどのようにスレッドセーフであり、次の手順が可能かということです。
- スレッド 1、同期ブロックに入り、ヘルパーが null であることを確認します。
- スレッド 1、この時点でモニターをあきらめます
- スレッド 2、オブジェクト モニターに入り、ヘルパーをインスタンス化します。
- スレッド 1 が戻ってきて、ヘルパー インスタンスを次のように再初期化します。
このソリューションが単一のチェック付きロックよりも優れているとは思いません。
java - アンチパターンとしてのロックのダブルチェック
このイディオムがアンチパターンであると主張する共通の信念と複数の情報源 ( wikiを含む) があります。
正しい実装が使用されている場合 (たとえば、volatileを使用) 、製品コードでそれを使用することに反対する引数は何ですか?
マルチスレッド環境で遅延初期化を実装するための適切な代替手段は何ですか? メソッド全体をロックすることはボトルネックになる可能性があり、最新の同期は比較的安価ですが、特に競合下では依然としてはるかに遅くなります。静的ホルダーは、言語固有で少し醜いハックのようです (少なくとも私にとっては)。Atomics ベースの実装は、従来の DCL とそれほど変わらないように見えますが、複数の計算が可能であったり、より複雑なコードが必要になったりします。たとえば、Scala はまだ遅延値を実装するために DCL を使用していますが、提案されている代替案ははるかに複雑に見えます。
java - 非静的値の遅延初期化
質問は実際には別の質問を参照しており、おそらく適切に定式化されていないため、重複としてクローズされました。
このコード サンプル (マルチスレッド環境で) の二重チェック ロックの代わりに、効果的な代替の遅延初期化イディオムは次のとおりです。
}
編集遅い操作を含めるように更新し、マルチスレッド環境に関する明示的な言及を追加しました
java - オブジェクトが何らかのメソッドによって構築される前に、Java はそのオブジェクトへの参照に書き込むことができますか?
二重チェックのロック パターンを使用しているときに、よく知られた落とし穴がありました (例と説明は「Concurrency in Practice」から引用)。
一部のスレッドは、オブジェクト自体がまだ構築中である間に、'resource' 変数の初期化された値を確認する場合があります。
問題は、リソース オブジェクトを何らかのメソッドで構築している場合に問題が残るかどうかです。いえ
createResource() メソッドでリソース オブジェクトがまだ構築中であるときに、一部のスレッドがリソース != null を true として評価できますか?
java - 不揮発性ダブルチェックロックは可能ですか?
これが私のシングルトンクラスです。
staticinstance
フィールドは揮発性ではないため、並べ替え/可視性の問題が発生します。それを解決するために、インスタンスval
フィールドは final になります。インスタンスは適切に構築されているため、インスタンスが表示される場合、クライアントは常にval
フィールドが初期化されていることを確認する必要があります。
ただし、別の問題があります-「インスタンス」フィールドの保護されていない読み取りが2つあり、クライアントが実際の値ではなくnullを取得できるように並べ替える(?)ことができます:
これを回避するには、ローカル変数を導入できるように感じます。
保護されていない値の読み取りは 1 つしかないため、これで問題が解決したように見えます。しかし...シングルスレッドのセマンティクスを変更せずに(ほとんど?)プログラムフローを変更しました。これは、この変換は安全であり、volatile との適切な事前発生関係を確立せずにこのコードを機能させる方法がないため、コンパイラが私の回避策を元に戻すことができるということですか?
c# - 複数回呼び出された PreApplicationStartMethod
PreApplicationStartMethod
属性によって装飾されたアセンブリ内のクラスのメソッドは、Application_Start
イベントが発生する前に呼び出されることを意図しています。たとえば、これはBuildManager
、ページ、コントロール、またはビューをコンパイルするときに、どのアセンブリ (Web アプリケーション内のアセンブリに加えて) を参照するかを知る方法です。
指摘されたメソッドが 1 回だけ呼び出されることを期待するのはごく自然なことです。結局のところ、これは初期化プロセスの一部であり、通常はアプリケーションごとに 1 回だけ実行されます。(データベースを 2 回作成する試みについてのみ言及します!!)
いくつかのトレース呼び出しを追加した後、メソッド (常にではなく、時々!) が 2 回呼び出されていることがわかりました。これを避けるために、クラスにブール値フィールドを追加して、次のような複数の呼び出しを防ぎました。
驚いたことに、このメソッドは再び 2 回呼び出されました。明らかな疑いは、2 つの異なるスレッドで呼び出されたということでした (初期化コードでは少し意味があるにもかかわらず)。 ダブルチェック ロックは、このような問題に対する明らかな解決策でした。そのため、コードを次のように変更しました。
これを実際に問題にしているのは、コードがネイティブ コードから呼び出されるという事実です。これは、トレースポイントからの $CALLER です。
だから、私の質問は明らかです、私は推測します: 何 (そしてもっと重要な理由!Application_Start
) は、イベントの前に複数回呼び出されるように指定されたメソッドを呼び出しますか?
c++ - スレッドセーフな遅延初期化: 静的 vs std::call_once vs ダブル チェック ロック
スレッドセーフな遅延初期化の場合、関数内の静的変数、std::call_once、または明示的な二重チェック ロックを使用する必要がありますか? 意味のある違いはありますか?
3つすべてがこの質問で見ることができます。
C++11 の二重チェック ロックの 2 つのバージョンが Google に表示されます。
Anthony Williamsは、明示的なメモリ順序付けによる二重チェック ロックと std::call_once の両方を示しています。彼は静的については言及していませんが、その記事は C++11 コンパイラが利用可能になる前に書かれた可能性があります。
Jeff Preshing は、詳細な記事で、二重チェック ロックのいくつかのバリエーションについて説明しています。彼は静的変数をオプションとして使用することについて言及しており、静的変数を初期化するためにコンパイラーがダブルチェックロックのコードを生成することさえ示しています。ある方法が他の方法よりも優れていると彼が結論付けているかどうかは、私には明らかではありません.
どちらの記事も教育的なものであり、そうする理由はないと私は感じています。静的変数または std::call_once を使用すると、コンパイラが自動的に実行します。
java - ダブルチェックロックで不変オブジェクトが安全なのはなぜですか?
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.htmlの下部には、次のように書かれています。
ダブルチェックされた不変オブジェクトのロック
Helper のすべてのフィールドが final であるなど、Helper が不変オブジェクトである場合、再確認されたロックは揮発性フィールドを使用しなくても機能します。不変オブジェクト (String や Integer など) への参照は、int や float とほぼ同じように動作する必要があるという考え方です。不変オブジェクトへの参照の読み取りと書き込みはアトミックです。
変更可能なもののサンプルと説明は次のとおりです。
うまくいかない一番の理由
それが機能しない最も明白な理由は、ヘルパー オブジェクトを初期化する書き込みとヘルパー フィールドへの書き込みが実行されたり、順不同で認識されたりする可能性があるためです。したがって、getHelper() を呼び出すスレッドは、ヘルパー オブジェクトへの null 以外の参照を参照できますが、コンストラクターで設定された値ではなく、ヘルパー オブジェクトのフィールドのデフォルト値を参照できます。
コンパイラーがコンストラクターへの呼び出しをインライン化する場合、コンストラクターが例外をスローしたり、同期を実行したりできないことをコンパイラーが証明できれば、オブジェクトを初期化する書き込みとヘルパー フィールドへの書き込みを自由に並べ替えることができます。
コンパイラがこれらの書き込みを並べ替えない場合でも、マルチプロセッサでは、別のプロセッサで実行されているスレッドによって認識されるように、プロセッサまたはメモリ システムがそれらの書き込みを並べ替える場合があります。
私の質問は、なぜ不変クラスに問題がないのですか? クラスが変更可能かどうかとの並べ替えの関係はわかりません。
ありがとう