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; } }
  }

,一个用于设置值的线程和多个读取值的线程。因此,可以使用lock()使所有读取和写入不间断。但我知道同步永远不会实现,总是有Val1 - Val2可能不等于Delta 我不太关心的机会。我更关心的是通过 getter 获得稳定的值。然而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

如果您需要 getter 返回稳定的结果,并且只需要保持内部同步,那么我建议您创建一个名为“Snapshot”的类(包含 Val1、Val2 和 Delta)或类似的东西。在您的设置器中,构建此类的新副本并将其交换为实例变量。在您的吸气剂中,只需返回快照的当前副本。只要调用者需要一致的体验,他们就会使用从单个 getter 调用返回的单个快照实例。

所以你必须放弃拥有多个 getter - 没有办法(没有外部同步)保证 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 回答