12

私は主にPOCOクラスとして設計されたクラスを持っており、さまざまなスレッドとタスクがその値を読み取ることができ、他の人だけがこれらの値をたまに更新するだけです。これは、ReaderWriterLockSlimにとって理想的なシナリオのようです。

問題は、クラスで、スレッドセーフである必要があるプロパティ、プロパティがブール値である場合、それはやり過ぎですか?それがintの場合はどうなりますか?日付時刻?

public class MyClass
{
  private bool _theValue = false;
  private ReaderWriterLockSlim _theValueLock = new ReaderWriterLockSlim();

  public bool TheValue
  {
    get
    {
      bool returnVal = false;
      try
      {
        _theValueLock.EnterReadLock();
        returnVal = _theValue;
      }
      finally
      { _theValueLock.ExitReadLock(); }
      return returnVal;
    }
    set
    {
      try
      {
        _theValueLock.EnterWriteLock();
        _theValue = value;
      }
      finally
      { _theValueLock.ExitWriteLock(); }
    }
  }
}

このコードはすべてやり過ぎで、単純です...

public bool TheValue { get; set; }

...十分でしょうか?タイプはブール値なので安全ですか?もしそうなら、それはいつ安全でなくなるのですか?バイト?int?日付時刻?

編集
私の基本的なアーキテクチャは、このクラスストアの状態にすることです。たぶん、このクラスへの書き込みを担当するサービスが1つあります。他のすべてのクラスは、この状態データに基づいてロジックを読み取り、実行できます。私はすべてのデータが一貫していることを確認するために最善を尽くしますが、以下に述べるように、私の主な関心事はデータの原子性と分裂でした。

結論
皆さんの回答に感謝します。すべてが貴重でした。私の主な関心事は、書き込み/読み取りの原子性でした(つまり、スプリンチングについて心配していました)。.NETプラットフォームの場合、問題の変数が4バイト未満の組み込み値型である場合、読み取りと書き込みはアトミックです(たとえば、shortとintは問題ありませんが、longとdoubleは問題ありません)。

4

3 に答える 3

8

これがどのように使用されているかに応じて、ブール揮発性をマークする必要がある場合があります。これには、プロパティへのバッキングフィールドが必要になります。

32ビット未満であるため、現在のようにこれを処理する必要はありませんReaderWriterLockSlim(AutoLayoutを使用している場合、詳細については、この投稿を参照するか、詳細については、メモリアクセスのアトミシティというタイトルのセクションを参照してください) ECMA 335仕様)。これより大きいタイプを使用している場合は、何らかの形式の同期が必要になります。

私がお勧めします:

public class MyClass
{
    private volatile bool _theValue = false;
    public bool TheValue 
    {
        get { return _theValue; } 
        set { _theValue = value; } 
    }
 }
于 2011-06-22T00:00:03.983 に答える
4

本当に安全なタイプはありません!より正確には、C#仕様では、4バイト未満の構造体タイプまたは参照の読み取りまたは割り当てがアトミックであることを保証しています。オペレーティングシステムが64ビットの場合、CLRは、8バイト未満の構造に対して同じことを保証することで少し良くなります。

ただし、値の割り当てや読み取りよりも複雑なものは、注意しないと、別の競合するスレッドによって中断される可能性があります。

これと同じくらい単純なものでさえ:

myBool = !myBool

競合するスレッドがmyBoolの値を変更すると、予期しない結果が生じる可能性があります。

そのようなことが起こらないようにしたい場合は、ロックを使用することをお勧めします。自分が何をしているのかを正確に理解していない限り、volatileキーワードの使用は強くお勧めしません。追加情報については、これらの ブログ 投稿を確認してください。

ただし、プロパティが1回の書き込みまたは1回の読み取り以外のことを行わない例では、ロックは役に立ちません。しかし、追加の治療があった場合はそうではありません。

于 2011-06-22T00:08:25.697 に答える
4

いくつかのオプションがあります。

  • 何もしない。
  • クラスを不変にします。
  • プレーンな古いを使用しlockます。
  • フィールドをとしてマークしますvolatile
  • Interlocked一連のメソッドを使用します。

aへの読み取りと書き込みはboolアトミックであることが保証されているため、何もする必要がない場合があります。これは、クラスの使用方法の性質に大きく依存します。Atomicityはスレッドセーフと同じではありません。それはその一面に過ぎません。

理想的な解決策は、クラスを不変にすることです。不変クラスは、他のスレッドによって変更できないため(または、まったく変更できないため)、通常はスレッドセーフです。ただし、これが実行できない場合もあります。

リストの次の好みは、昔ながらのものlockです。取得と解放のオーバーヘッドはごくわずかです。実際、特に変数の読み取り/書き込みだけを行っている場合は、ほとんどの状況でalockが打ち負かされることがわかると思います。ReaderWriterLockSlim私自身の個人的なテストでは、RWLSのオーバーヘッドは。よりも約5倍遅いことが示されていますlock。したがって、読み取り操作が異常に長く、書き込み操作を大幅に上回っていない限り、RWLSは役に立ちません。

ロックのオーバーヘッドが心配な場合は、必ずフィールドにとしてマークを付けてvolatileください。volatileこれは、すべての並行性の問題を解決する魔法の弾丸ではないことを覚えておいてください。の代わりとなるものではありませんlock

于 2011-06-22T01:40:10.647 に答える