22

boolやなどの C# の特定のプリミティブ型に対する読み取りと書き込みintはアトミックです。

(C# 言語仕様のセクション 5.5、「5.5 変数参照の原子性」を参照してください。)

しかし、プロパティを介してそのような変数にアクセスするにはどうすればよいでしょうか? それらがアトミックでスレッドセーフでもあると仮定するのは合理的ですか? たとえば、以下の読み取りはMyPropertyアトミックでスレッドセーフですか?:

public bool MyProperty { get { return _foo; } }

自動実装されたプロパティはどうですか?

public bool MyProperty { get; }
4

6 に答える 6

31

「アトミック」と「スレッドセーフ」をより厳密に区別する必要があります。あなたが言うように、書き込みはほとんどの組み込みの値の型と参照に対してアトミックです。

ただし、それはそれらがスレッドセーフであることを意味しません。値 "A" と "B" の両方が書き込まれている場合、スレッドはその間に何も表示されないことを意味します。(たとえば、1 から 4 への変更は、5 や 2 を表示したり、1 や 4 以外の値を表示したりすることはありません。)変数に値が書き込まれるとすぐに、1 つのスレッドが値 "B" を認識するという意味ではありません。そのためには、揮発性の観点からメモリ モデルを調べる必要があります。通常、ロック変数や揮発性変数によって取得されるメモリ バリアがない場合、メイン メモリへの書き込みが遅延し、読み取りが進行する可能性があります。

カウンターがあり、最新の値を要求したが、メモリバリアがないために最新の値を受け取っていない場合、各操作がアトミックである可能性があるとしても、それをスレッドセーフと呼ぶことは合理的ではないと思います。

ただし、これはプロパティとは何の関係もありません。プロパティは、単に構文糖衣を使用したメソッドです。スレッド化に関して特別な保証はありません。.NET 2.0 メモリ モデルには、ECMA モデルよりも多くの保証があり、メソッドのエントリと終了に関して保証を行う可能性があります。これらの保証はプロパティにも適用されるはずですが、そのようなルールの解釈については神経質になるでしょう: メモリ モデルについて推論するのは非常に難しい場合があります。

于 2009-07-20T06:00:48.600 に答える
2

自動生成されたコードを調べると、自動生成されたプロパティがスレッド セーフではないことがわかります。これらは、生成されたフィールドに対する単純な get/set です。実際、これを行うとパフォーマンスへの影響が大きすぎます (特に必要がない場合)。

さらに、複数のスレッドから int/bool 値にアクセスする予定がある場合は、それ (フィールド) をvolatileとしてマークする必要があります。これにより、基本的に CPU レジスタに関連するマルチスレッドの問題が回避されます。(これはロックに追加するものであり、代替手段ではありません)

于 2009-07-20T05:53:13.873 に答える
2

私はあなたがここで何を求めているのか少しわかりません。2 つの質問のうちの 1 つを尋ねているようです

  1. _fooMyProperty の呼び出し中の読み取りはアトミックですか?
  2. MyProperty の戻り値はアトミックに設定されていますか?

#1の答えはイエスです。C# 言語仕様 (および CLI) で述べられているように、指定された特定の型の変数の読み取りと書き込みはアトミックであることが保証されています。型「bool」はそれらの型の 1 つです。

#2 に関しては、CLI 仕様のセクション 12.6.6 を参照するのが最適です。それは次のように述べています

適合する CLI は、ネイティブ ワード サイズ (ネイティブ int 型のサイズ) を超えない適切に配置されたメモリ位置への読み取りおよび書き込みアクセスがアトミックであることを保証するものとします。

MyProperty の戻り値を使用することを考慮すると、値を読み取るか書き込む必要があるため、アトミックに設定されていると想定しても安全です。

于 2009-07-20T05:58:42.457 に答える
1

原子性とは、複数のスレッドが変数に書き込んでいる場合、その値が壊れないことを意味します (たとえば、2 バイトを占める場合、スレッド 1 の上位バイトとスレッド 2 の下位バイトを取得することはありません)。変数がスレッドセーフであることを意味するわけではありません。あるスレッドが別のスレッドの変更を認識しないなど、通常のスレッドの問題が引き続き発生する可能性があります。

スレッドセーフのためには、ロックを使用する必要があります (または揮発性ですが、これは理由付けが難しいです)。プロパティについて特別なことは何もありません - それらも明示的にスレッドセーフにする必要があります。

于 2009-07-20T06:01:33.497 に答える
0

プロパティには何でも入れることができます。

    Public Property foo() As Boolean
        Get
           goToLunch()
           barbecueRibs()
           return m_foo
        End Get
        Set(ByVal value As Boolean)
           takeANap()
           accessDatabase()
           messUpOtherVariables()
           m_foo = value
        End Set
    End Property
于 2009-07-20T06:11:59.717 に答える
0

私はそうは思わないでしょう。プロパティは基本的に、操作を少し簡単にするために構文糖衣を少し加えた単なるメソッドです。したがって、デフォルトでは、通常のメソッド呼び出しよりもスレッドセーフではありません (つまり、スレッドセーフではありません)。

于 2009-07-20T05:53:59.440 に答える