Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net lock()在这里有意义吗?_.net_Multithreading_Locking_Atomic_Interlocked - Fatal编程技术网

.net lock()在这里有意义吗?

.net lock()在这里有意义吗?,.net,multithreading,locking,atomic,interlocked,.net,Multithreading,Locking,Atomic,Interlocked,我有一个简单的类,如: 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 val

我有一个简单的类,如:

  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()

但代码对我来说似乎很愚蠢。我不知道


那么
lock()
有意义吗?我是否应该使用
Interlocked.Exchange()
来提高性能?或者我还能做什么?

对于我将使用的多个读者/作者场景


对于多个读写器场景,我将使用


您需要锁定整个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 /* ... */ }
}

您需要锁定整个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 /* ... */ }
}

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

因此,您必须放弃使用多个getter,否则就无法(没有外部同步)保证Val1、Val2和Delta是一致的



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

因此,您必须放弃使用多个getter,否则就无法(没有外部同步)保证Val1、Val2和Delta是一致的




嗯<代码>变量foo=new XXX();var v1=foo.Val1;var v2=foo.Val2;var d=foo.Delta;断言相等(增量,v1-v2)可能仍然会失败。请告诉我,除非我倾向于使用互斥作为个人偏好。@Spaceghost:没有区别。您的线程仍然可以在读取foo.Delta和foo.V1.Huh之间被抢占<代码>变量foo=new XXX();var v1=foo.Val1;var v2=foo.Val2;var d=foo.Delta;断言相等(增量,v1-v2)可能仍然会失败。请告诉我,除非我倾向于使用互斥作为个人偏好。@Spaceghost:没有区别。您的线程仍然可以在读取foo.Delta和foo.V1之间被抢占。标准的
锁通常比
ReaderWriterLockSlim
便宜,这取决于读写比。@LukeH-这正是我想要的。谢谢。一个标准的
通常比
读写锁
便宜,这取决于读写比。@LukeH-这正是我想要的。谢谢。+1,但是
联锁的.Exchange
调用是不必要的,因为引用赋值保证是原子的。这样做可以完全无锁。@LukeH-我真的记不起来了。如果这是真的,
interlocated.Exchange(Object,Object)
的目的是什么?我想您可能希望将旧值作为原子操作的一部分:例如,
var oldVal=\u val_val=newVal
,这两个操作都是单独的原子操作,但不能保证
oldVal
在被
newVal
@LukeH覆盖之前的某一点包含
\u val
的内容-是,我忘了返回值在那里很有用。@sad_man-你必须将
xxx.Current
存储到读取代码的变量中,然后使用该变量保持一致性。因此,我引用了“他们将使用从单个getter调用返回的单个快照实例”+1,但是
Interlocked.Exchange
调用是不必要的,因为引用分配保证是原子的。这样做可以完全无锁。@LukeH-我真的记不起来了。如果这是真的,
interlocated.Exchange(Object,Object)
的目的是什么?我想您可能希望将旧值作为原子操作的一部分:例如,
var oldVal=\u val_val=newVal
,这两个操作都是单独的原子操作,但不能保证
oldVal
在被
newVal
@LukeH覆盖之前的某一点包含
\u val
的内容-是,我忘了返回值在那里很有用。@sad_man-你必须将
xxx.Current
存储到读取代码的变量中,然后使用该变量保持一致性。因此我引用了“他们将使用从单个getter调用返回的单个快照实例”
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; } }

  }