[解決済み] 参照代入はアトミックなのに、なぜInterlocked.Exchange(ref Object, Object)が必要なのか?
質問
マルチスレッドのasmxウェブサービスで、独自のSystemData型のクラスフィールド_allDataを持っていましたが、これはいくつかの要素で構成されています。
List<T>
と
Dictionary<T>
とマークされている
volatile
. システムデータ (
_allData
) は時々リフレッシュされます。
newData
という別のオブジェクトを作り、そのデータ構造を新しいデータで埋めることで行います。それが終わると、私はただ
private static volatile SystemData _allData
public static bool LoadAllSystemData()
{
SystemData newData = new SystemData();
/* fill newData with up-to-date data*/
...
_allData = newData.
}
これは、割り当てがアトミックであり、古いデータへの参照を持つスレッドがそれを使い続け、残りは割り当て直後に新しいシステムデータを持つので、うまくいくはずです。しかし、私の同僚は
volatile
キーワードと単純な代入を使う代わりに、私は
InterLocked.Exchange
というのは、あるプラットフォームでは参照代入がアトミックであることが保証されないからだそうです。さらに
the _allData
というフィールドを
volatile
という
Interlocked.Exchange<SystemData>(ref _allData, newData);
produces warning "a reference to a volatile field will not be treated as volatile" これについてどう考えればいいでしょうか?
どのように解決すればよいのでしょうか。
ここには数多くの質問があります。一度に1つずつ考えてみましょう。
参照代入はアトミックであるのに、なぜInterlocked.Exchange(ref Object, Object)が必要なのでしょうか?
参照代入はアトミックです。Interlocked.Exchangeは参照渡しを行うだけではありません。変数の現在値を読み込み、古い値を退避させ、新しい値を変数に代入する、という作業をアトミックに行います。
私の同僚は、いくつかのプラットフォームでは参照代入がアトミックであることが保証されないと言いました。私の同僚は正しかったのでしょうか。
いいえ。参照代入は、すべての .NET プラットフォームでアトミックであることが保証されています。
私の同僚は誤った前提から推論しています。それは、彼らの結論が正しくないということですか?
そうとは限りません。あなたの同僚は、悪い理由のために良いアドバイスをしているのかもしれません。もしかしたら、Interlocked.Exchange を使うべき理由が他にあるのかもしれません。ロックフリーのプログラミングは非常に難しく、その分野の専門家が支持する確立されたプラクティスから外れた瞬間に、あなたは雑草の中に入り込み、最悪のレース状態を引き起こすリスクを負っているのです。私はこの分野の専門家でもなければ、あなたのコードの専門家でもないので、どちらか一方に判断することはできません。
produces warning "a reference to a volatile field will not be treated as volatile" これについてどう考えればよいのでしょうか。
一般的になぜこれが問題なのかを理解する必要があります。そうすれば、なぜこの特定のケースで警告が重要でないのかの理解につながります。
コンパイラがこの警告を出す理由は、フィールドをvolatileとマークすることは、"このフィールドは複数のスレッドで更新されることになるからです。このフィールドの値をキャッシュするコードを生成してはいけませんし、このフィールドの読み取りまたは書き込みがプロセッサキャッシュの不整合によって"時間的に前や後ろに移動しないことを確認しなければなりません。
(私は、あなたがすでにこれらすべてを理解していると仮定しています。もし、volatile の意味とそれがプロセッサ キャッシュのセマンティクスにどのように影響するかを詳細に理解していないのであれば、volatile がどのように機能するかを理解しておらず、volatile を使用すべきではないでしょう。ロックフリーのプログラムを正しく作るのは非常に困難です。あなたのプログラムが、偶然に正しいのではなく、それがどのように動作するかを理解しているから正しいのだということを確認してください)。
ここで、volatileフィールドのエイリアスとなる変数を、そのフィールドにrefを渡して作ったとします。呼び出されたメソッドの内部では、コンパイラーは参照が揮発性のセマンティクスを持つ必要があることを知る理由が全くありません! コンパイラは、揮発性フィールドの規則を実装していないメソッドのコードを喜んで生成しますが、変数 は は揮発性フィールドです。これはロックフリーのロジックを完全に破壊してしまう可能性があります。 常に は揮発性セマンティクスでアクセスされる。あるときは揮発性で、あるときはそうでないという扱いは意味がありません。 常に そうでなければ、他のアクセスにおける一貫性を保証することはできません。
そのため、これを行うとコンパイラは警告を発します。おそらく、注意深く開発したロックフリーのロジックを完全に台無しにしてしまうからです。
もちろん、Interlocked.Exchange は は volatile フィールドを予期して正しいことをするように書かれています。したがって、この警告は誤解を招くものです。 私たちがすべきことは、Interlocked.Exchange のようなメソッドの作者が、メソッドに「ref を取るこのメソッドは変数に volatile セマンティクスを強制するので警告を抑止してください"」という属性を付けることができるような仕組みを実装することでした。 おそらく、コンパイラの将来のバージョンでは、そうすることになるでしょう。
関連
-
[解決済み】C#で四捨五入する方法
-
[解決済み】トランスポート接続からデータを読み取れない:既存の接続は、リモートホストによって強制的に閉じられました。
-
[解決済み】WPFでXamlファイルにコメントを追加する方法は?
-
[解決済み] EntityTypeにキーが定義されていないエラー
-
[解決済み】HRESULTからの例外:0x800A03ECエラー
-
[解決済み】「namespace」なのに「type」のように使われる。
-
[解決済み】名前 'ViewBag' が現在のコンテキストに存在しない - Visual Studio 2015
-
[解決済み】Nullableオブジェクトは値を持たなければならない?
-
[解決済み】オブジェクトを渡すときに'ref'キーワードを使用するのはなぜですか?
-
[解決済み】なぜJsonRequestBehaviorが必要なのでしょうか?
最新
-
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 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】エラー。「戻り値を変更できません」 C#
-
[解決済み】スクリプトクラスが見つからないので、スクリプトコンポーネントを追加できない?
-
[解決済み] 保護レベルによりアクセス不能になりました。
-
[解決済み】C#はJavaのcharAt()と同等?)
-
[解決済み】バックスラッシュを含むパス文字列のエスケープシーケンスが認識されない件
-
[解決済み】Unity3DでOnTriggerEnterが動作しない件
-
[解決済み】値が期待した範囲に収まらない
-
[解決済み】C# - パスに不正な文字がある場合
-
[解決済み】WSACancelBlockingCallの例外について
-
[解決済み] 2つのリストを結合する