参照割り当てはアトミックなので、なぜinterlocked.exchange(ref、object、object)が必要なのですか?

StackOverflow https://stackoverflow.com/questions/2192124

質問

私のマルチスレッドASMX Webサービスでは、クラスフィールド_Alldataがありました。 List<T>Dictionary<T> ASとしてマークされています 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 フィールドAS volatile

Interlocked.Exchange<SystemData>(ref _allData, newData); 

警告を生成する「揮発性フィールドへの参照は揮発性として扱われない」これについてどう思うべきか?

役に立ちましたか?

解決

ここには多くの質問があります。それらを一度に考慮してください:

参照割り当てはアトミックなので、なぜinterlocked.exchange(ref、object、object)が必要なのですか?

参照割り当てはアトミックです。 interlocked.exchangeは、参照割り当てのみを実行しません。変数の現在の値の読み取りを行い、古い値を隠して、すべてが原子操作として変数に新しい値を割り当てます。

私の同僚は、一部のプラットフォームでは、参照の割り当てが原子的であることを保証するものではないと言いました。私の同僚は正しかったですか?

いいえ。参照割り当ては、すべての.NETプラットフォームでアトミックであることが保証されています。

私の同僚は、虚偽の前提からの理由です。それは彼らの結論が間違っていることを意味しますか?

必ずしも。あなたの同僚は、悪い理由であなたに良いアドバイスを与えることができます。おそらく、interlocked.exchangeを使用する必要がある他の理由があります。ロックフリーのプログラミングは非常に困難であり、あなたがこの分野の専門家が支持する確立された慣行から離れる瞬間、あなたは雑草に陥り、最悪の種類の人種条件を危険にさらしています。私はこの分野の専門家でもあなたのコードの専門家でもないので、何らかの方法で判断を下すことはできません。

警告を生成する「揮発性フィールドへの参照は揮発性として扱われない」これについてどう思うべきか?

これが一般的に問題である理由を理解する必要があります。これは、この特定のケースで警告が重要でない理由を理解することにつながります。

コンパイラがこの警告を与える理由は、揮発性としてフィールドをマークすることを意味するためです。このフィールドは、プロセッサキャッシュの矛盾を介して「前後に移動して時間をかけて移動する」ものではありません。」

(私はあなたがすでにそれをすべて理解していると思います。あなたが揮発性の意味とそれがプロセッサキャッシュセマンティクスにどのように影響するかを詳細に理解していない場合、あなたはそれがどのように機能するかを理解しておらず、揮発性の使用をすべきではありません。ロックフリープログラム正しくするのは非常に難しいです。偶然には正しいものではなく、それがどのように機能するかを理解しているので、プログラムが正しいことを確認してください。)

ここで、Refをそのフィールドに渡すことにより、揮発性フィールドのエイリアスである変数を作成するとします。呼び出された方法内では、コンパイラには、リファレンスに揮発性セマンティクスが必要であることを知る理由はまったくありません!コンパイラは、揮発性フィールドのルールを実装できない方法のコードを元気に生成しますが、変数は 揮発性フィールド。それはあなたのロックフリーのロジックを完全に破壊することができます。仮定は、常に揮発性フィールドがあるということです いつも 揮発性セマンティクスでアクセス。それを時々揮発性として扱うことは意味がなく、他の時もありません。必ず いつも それ以外の場合は、他のアクセスの一貫性を保証することはできません。

したがって、コンパイラはこれを行うと警告します。なぜなら、それはおそらくあなたの慎重に開発されたロックフリーのロジックを完全に台無しにするからです。

もちろん、Interlocked.Exchange 揮発性フィールドを期待し、正しいことをするために書かれています。したがって、警告は誤解を招きます。私はこれをとても後悔しています。私たちがすべきだったことは、interlocked.exchangeのような方法の著者が「この方法を取るこの方法を変数に強制するため、警告を抑制する」というメソッドに属性を置くことができるメカニズムを実装することです。おそらく、コンパイラの将来のバージョンでは、そうするでしょう。

他のヒント

あなたの同僚が間違っているか、彼はC#言語の仕様がそうでないことを知っています。

5.5可変参照の原子性:

「次のデータ型を読み、書き込みます:Bool、Char、Byte、Sbyte、Short、Ushort、Uint、Int、Float、および参照タイプ。」

したがって、腐敗した価値を得るリスクなしに、揮発性の参照に書き込むことができます。

もちろん、どのスレッドが新しいデータを取得するかを決定する方法に注意して、一度に複数のスレッドが行うリスクを最小限に抑える必要があります。

interlocked.exchange <t>

指定されたタイプTの変数を指定された値に設定し、原子操作として元の値を返します。

それは変更されて元の値を返します。あなたはそれを変更したいだけでなく、Guffaが言ったように、それはすでに原子的です。

プロファイラーがアプリケーションのボトルネックであることが証明されていない限り、安全でないロックを検討する必要があります。コードが正しいことを理解し、証明する方が簡単です。

Iterlocked.Exchange() アトミックだけでなく、メモリの可視性も担当します。

次の同期関数は、適切な障壁を使用して、メモリの順序を確保することを保証します。

重要なセクションに入るか、出発する関数

同期オブジェクトを信号する関数

待機機能

インターロック機能

同期とマルチプロセッサの問題

これは、原子性に加えて、次のことを保証することを意味します。

  • それを呼ぶスレッドのために:
    • 指示の並べ替えは行われません(コンパイラ、実行時間、またはハードウェアによって)。
  • すべてのスレッドについて:
    • この命令がこの命令が行った変更を見る前に起こる記憶には読みません。
    • この指示の後にすべての読み取りでは、この指示によって行われた変更が表示されます。
    • この命令の変更が行われた後、すべてのメモリに書き込みます。この命令の変更がメインメモリに達した後に行われます(この命令の変更を完了したときにメインメモリにフラッシュし、ハードウェアがタイミングで所有しないようにします)。
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top