1

私は次のような単純なクラスを持っています:

  public class XXX
  {
    double val1;
    double val2;
    double delta;
    public void SetValues(double v1, double v2)
    {
      val1 = v1;
      val2 = v2;
      delta = val1 - val2;
    }

    public double Val1 { get { return val1; } }
    public double Val2 { get { return val2; } }
    public double Delta { get { return delta; } }
  }

、値を設定するための1つのスレッドと、値を読み取る複数のスレッド。したがってlock()、すべての読み取りと書き込みを中断しないようにするために使用できます。しかし、同期が達成されることは決してないことを私は知っています。私があまり気にしないVal1 - Val2のと同じではない可能性が常にあります。私の懸念は、ゲッターを介して安定した値を取得することです。ただし、ほとんどの場合、読者が作業するため、この状況ではコストがかかります。Delta lock()

私の頭に浮かぶ次善の策は使用することですInterlocked.Exchange()

    public void SetValues(double v1, double v2)
    {
      Interlocked.Exchange(ref val1, v1);
      Interlocked.Exchange(ref val2, v2);
      Interlocked.Exchange(ref delta, v1 - v2);
    }

    public double Val1 { 
      get 
      {
        double val = 0;
        Interlocked.Exchange(ref val, val1);
        return val; 
      } 
    }

しかし、コードは私にはかなりばかげているようです。知らない。

それでlock()意味がありますか?Interlocked.Exchange()パフォーマンスを向上させるためにを使用する必要がありますか?または他に何ができますか?

4

3 に答える 3

3

SetValuesメソッド全体をロックする必要があります。

private object lockObject = new object();

public void SetValues(double v1, double v2)
{
  lock(lockObject)
  {
    val1 = v1;
    val2 = v2;
    delta = val1 - val2;
  }
}

public double Val1 { get { lock(lockObject) { return val1; } } }
public double Val2 { get { lock(lockObject) { return val2; } } }
public double Delta { get { lock(lockObject) { return delta; } } }

読者は、いくつかのステップで読み取るため、一緒に属していないVal1、Val2、およびDeltaを取得できます。

Val1、Val2、およびDeltaを、一度取得されて変更されない値オブジェクトに入れることができます。

public Values Val1
{ 
  get 
  { 
    lock(lockObject) 
    { 
      // create a consistent object which holds a copy of the values
      return new Values(val1, val2, delta); 
    } 
  }
}

struct Values
{
  // ...
  public double Val1 { get /* ... */ }
  public double Val2 { get /* ... */ }
  public double Delta  { get /* ... */ }
}
于 2011-03-14T14:58:40.497 に答える
2

複数のリーダー/ライターのシナリオでは、ReaderWriterLockSlimを使用します。

Represents a lock that is used to manage access to a resource, 
allowing multiple threads for reading or exclusive access for writing.

Use ReaderWriterLockSlim to protect a resource that is read by multiple 
threads and written to by one thread at a time. ReaderWriterLockSlim 
allows multiple threads to be in read mode, allows one thread to be in 
write mode with exclusive ownership of the lock, and allows one thread 
that has read access to be in upgradeable read mode, from which the 
thread can upgrade to write mode without having to relinquish its 
read access to the resource.
于 2011-03-14T14:57:40.480 に答える
2

ゲッターが安定した結果を返す必要があり、内部同期のみを維持する必要がある場合は、「Snapshot」(Val1、Val2、およびDeltaを含む)などのクラスを作成することをお勧めします。セッターで、このクラスの新しいコピーを作成し、インスタンス変数に交換します。ゲッターで、スナップショットの現在のコピーを返すだけです。呼び出し元が一貫したエクスペリエンスを必要とする限り、単一のゲッター呼び出しから返された単一のスナップショットインスタンスを使用します。

したがって、複数のゲッターを持つことを放棄する必要があります-Val1、Val2、およびDeltaが他の方法で一貫していることを保証する方法は(外部同期なしでは)ありません。


public class XXX
  {
    public class Snapshot {
      double val1;
      double val2;
      double delta;
      public Snapshot (double val1,double val2)
      {
         this.val1 = val1;
         this.val2 = val2;
         this.delta = val1 - val2;
      }
      public double Val1 { get { return val1; } }
      public double Val2 { get { return val2; } }
      public double Delta { get { return delta; } }
    }
    Snapshot _current;
    public void SetValues(double v1, double v2)
    {
      Snapshot s = new Snapshot(v1,v2);
      /* If there were subsequent steps needed to get the snapshot "ready", you could do them here.
         Otherwise, I think you can do this as a single assignment into _current above */
      _current = s;
    }

    public Snapshot Current { get { return _current; } }

  }
于 2011-03-14T15:03:24.393 に答える