【问题标题】:Threads communicating without locking线程在没有锁定的情况下进行通信
【发布时间】:2013-01-08 05:47:39
【问题描述】:

如果我可以保证我的整个应用程序中只有一个方法会写入某个变量,那么我可以允许我的应用程序中的其他方法安全地读取该值吗?

如果是这样,我可以在不锁定变量的情况下摆脱这个噱头吗?

在这种情况下,我正在做(或者,尝试做,或者想要做)是让一个线程中的一个方法将一个值放入变量中,然后其他线程中的其他方法将读取该值并做出决定。

一个很好的选择是锁定写入,同时允许读取。

在这里查看MSDN page on lock 并没有看到这样做的方法。

【问题讨论】:

  • 边读边写并不是最好的主意。当对象已经更新时,您可以阅读混乱。
  • @Kamil 是的,正确的。读完这篇文章后,我对另一个项目进行了第二次检查。
  • @EricPetroelje:请参阅 Marc Gravell 的回答。问题是当更新不是原子的。例如,如果更新的值是一个 int,那么没有问题。如果更新的值是一个由多个整数组成的结构(例如,一个点类),那么它可能是一个真正的问题。这就是马克所说的“撕裂”。
  • @Eric 更改引用确实保证是原子的和安全的;语言保证了这一点。但是,如果代码更新了现有对象的 properties:如果没有同步,坏事可能会发生。如果您有 referenceimmutable 类,那么您随时可以安全地更改引用... 但是所有调用者都必须PROMISE 为引用 ONCE 拍摄快照,然后使用该快照。不int x = Foo.X; int y = Foo.Y - 它必须是var snap = Foo; int x = snap.X; int y = snap.Y;

标签: c# locking


【解决方案1】:

与往常一样,这在很大程度上取决于上下文。

  • 在紧密循环中读取的变量可能存储在寄存器或本地缓存中,因此除非您有“栅栏”,否则不会注意到任何变化; volatile 将解决这个问题,但作为副作用而不是明确的意图;大多数人(包括我)都无法正确定义 volatile 的含义 - 所以在将其用作“修复”时要非常小心。
  • 过大的类型(大型结构)不会是原子的(用于读取或写入) - 并且无法安全处理而没有撕裂的风险
  • 一个对象或值可能涉及多个子值;如果它们没有自动更改,可能会导致问题

但是,您可能会发现Interlocked 无需lock 即可解决您的大部分问题。同时,没有争议的lock 的速度疯狂,即使是有争议的lock 仍然惊人地快。坦率地说,我不确定你的想法是否值得:一个单位 lock 几乎可以肯定是足够快的,只要你先lock之外进行思考,并且只有在您知道要进行的更改时才使用lock

也有ReaderWriterLockSlim,但实际上提高性能的情况很少——根据我的经验,最简单的方法通常是最快的,表示lockInterlockedReaderWriterLockSlim 是一个更复杂的野兽,专为更复杂的场景而设计,因此有一点开销。不是大量数量,但足以让它值得仔细观察。

【讨论】:

  • @EricPetroelje 是的,它适用,因为他添加了限定条件“除非你添加栅栏”,这正是 volatile 所做的。
  • +1 for ... “无竞争的锁非常快,即使有竞争的锁仍然快得惊人。”
  • 我刚刚在The MSDN lock pageThe MSDN ReaderWriterLockSlim page 上花了一些时间,我的大部分时间都只是DUH!您(或任何正在阅读的人)是否愿意为变量和三个可以读写的类中的三个方法演示 lock 机制的正确语法和调用?随便称呼他们; Comm.BackGroundRx, SomeButtonClick, xClass.Thread3, MarcsClass.anyOldVariable 随便。
  • @User.1 lock===Monitor,不是ReaderWriterLockSlim,但这很容易:得到它:lock(someLock) { return theField; };设置它:lock(someLock) { theField = value; }
  • @User.1 是的,上面大约 2 行,或者在 MSDN 上;p
猜你喜欢
  • 2013-10-28
  • 1970-01-01
  • 1970-01-01
  • 2011-01-24
  • 1970-01-01
  • 2017-02-13
  • 1970-01-01
  • 2014-05-01
相关资源
最近更新 更多