[解決済み] 揮発性 vs. 連動性 vs. ロック性
質問
あるクラスが
public int counter
フィールドは、複数のスレッドからアクセスされます。この
int
はインクリメントまたはデクリメントされるだけです。
このフィールドをインクリメントするには、どの方法を使うべきか、またその理由は?
-
lock(this.locker) this.counter++;
, -
Interlocked.Increment(ref this.counter);
, -
のアクセスモディファイアを変更します。
counter
をpublic volatile
.
今、私が発見したのは
volatile
を削除しています。
lock
ステートメントを使用し
Interlocked
. しかし、これをしない理由はあるのでしょうか?
どのように解決するのですか?
最悪(実際には動作しない)
<ブロッククオート
のアクセス修飾子を変更する。
counter
から
public volatile
他の方もおっしゃっていますが、これ単体では実は全く安全ではありません。のポイントは
volatile
複数の CPU で動作する複数のスレッドが、データをキャッシュしたり、命令を並べ替えたりできることです。
もし、それが
ではない
volatile
で、CPU Aが値をインクリメントした場合、CPU Bが実際にそのインクリメントされた値を見るのは、しばらく経ってからとなり、問題が発生する可能性があります。
もし、それが
volatile
これは、2つのCPUが同時に同じデータを見ることができるようにするだけです。これは、あなたが避けようとしている問題である、読み込みと書き込みのインターリーブ操作を止めるものではありません。
セカンドベスト
<ブロッククオート
lock(this.locker) this.counter++
;
これは、安全に行うことができます(ただし、忘れずに
lock
をアクセスする他のすべての場所で
this.counter
). によってガードされている他のコードを他のスレッドが実行するのを防ぎます。
locker
.
また、ロックを使用することで、上記のような複数CPUによる並べ替えの問題を防ぐことができ、これは素晴らしいことです。
問題は、ロックに時間がかかること、そして
locker
を他の場所で使用すると、他のスレッドを無意味にブロックしてしまう可能性があります。
ベスト
<ブロッククオート
Interlocked.Increment(ref this.counter);
これは、読み込み、インクリメント、書き込みを「一発」で行うので安全であり、中断されることはありません。このため、他のコードに影響を与えることはありませんし、他の場所をロックすることを覚える必要もありません。また、非常に高速です(MSDNによると、最近のCPUでは、これは文字通り1つのCPU命令であることが多いようです)。
しかし、他のCPUの再順序付けを回避できるのか、揮発性とインクリメントを組み合わせる必要があるのか、まったくわかりません。
インターロックノートです。
- インターロックされたメソッドは、コアやCPUの数に関係なく連続的に安全です。
- インターロックされたメソッドは、実行する命令の周りに完全なフェンスを適用するため、順序の入れ替えは起こりません。
- インターロック・メソッド volatileフィールドへのアクセスを必要としない、あるいはサポートしない。 volatileは与えられたフィールドに対する操作の周りに半分のフェンスを置き、interlockedは完全なフェンスを使用するからです。
脚注:volatileが実際に適していること。
として
volatile
は、このようなマルチスレッドの問題を防ぐことはできませんが、何のためにあるのでしょうか?例えば、2つのスレッドがあり、1つは常に変数に書き込みをする (例えば
queueLength
と、その同じ変数から常に読み取るものです。
もし
queueLength
が揮発性でない場合、スレッドAは5回書き込むことができますが、スレッドBはこれらの書き込みが遅れている(あるいは間違った順序である可能性もある)と見なすかもしれません。
解決策としてはロックすることですが、この状況ではvolatileを使用することもできます。これにより、スレッドBは常にスレッドAが書き込んだ最新のものを見ることができるようになります。しかし、このロジックは のみ は、決して読まない書き手と、決して書かない読み手がいる場合に有効です。 そして 書き込むものがアトム値である場合。読み取り・変更・書き込みを1回でも行うと、すぐにInterlockedオペレーションに移行するか、Lockを使用する必要があります。
関連
-
[解決済み] [Solved] 1つ以上のエンティティで検証に失敗しました。詳細は'EntityValidationErrors'プロパティを参照してください [重複]。
-
[解決済み】Ajax処理で「無効なJSONプリミティブ」と表示される件
-
[解決済み] [Solved] アセンブリ System.Web.Extensions dll はどこにありますか?
-
[解決済み】EF 5 Enable-Migrations : アセンブリにコンテキストタイプが見つかりませんでした
-
[解決済み] UnityでOnCollisionEnterが呼ばれない
-
[解決済み】"指定されたパスのフォーマットはサポートされていません。"
-
[解決済み】ユーザー設定値を別のユーザー設定値で設定する
-
[解決済み] なぜList<T>を継承しないのですか?
-
[解決済み] volatileキーワードは何に役立つのでしょうか?
-
[解決済み] lock(this){...}はなぜダメなのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] 保護レベルによりアクセス不能になりました。
-
[解決済み】なぜこのコードはInvalidOperationExceptionを投げるのですか?
-
[解決済み】Socket.Selectがエラー "An operation was attempted on something that is not a socket" を返す。
-
[解決済み] UnityでOnCollisionEnterが呼ばれない
-
[解決済み】Visual studio 2019がデバッグ時にフリーズする件
-
[解決済み】"指定されたパスのフォーマットはサポートされていません。"
-
[解決済み】2つ(またはそれ以上)のリストを1つに統合する(C# .NETで
-
[解決済み】エラー「必要なフォーマルパラメータに対応する引数が与えられていない」を解決する?
-
[解決済み】別のスレッドがこのオブジェクトを所有しているため、呼び出し側のスレッドはこのオブジェクトにアクセスできない
-
[解決済み】Nullableオブジェクトは値を持たなければならない?