易失性与联锁对抗锁定

假设一个类有一个由多个线程访问的public int counter字段。 此int仅递增或递减。 web

要增长此字段,应使用哪一种方法,为何? 缓存

  • lock(this.locker) this.counter++;
  • Interlocked.Increment(ref this.counter);
  • counter的访问修饰符更改成public volatile

既然我发现了volatile ,我一直在删除许多lock语句和Interlocked的使用。 可是有理由不这样作吗? 多线程


#1楼

我是第二个Jon Skeet的回答,并但愿为想要了解更多关于“volatile”和Interlocked的人们添加如下连接: 优化

原子性,波动性和不变性是不一样的,第一部分 - (Eric Lippert的编码中的神话般的冒险) this

原子性,波动性和不变性是不一样的,第二部分 编码

原子性,波动性和不变性是不一样的,第三部分 spa

Sayonara Volatile - (2012年出现的Joe Duffy博客的Wayback Machine快照) 线程


#2楼

互锁功能不会锁定。 它们是原子的,这意味着它们能够完成而不会在增量期间进行上下文切换。 因此没有死锁或等待的可能性。 code

我会说你应该老是喜欢锁定和增量。 orm

若是您须要在一个线程中写入以在另外一个线程中读取,而且您但愿优化器不对变量从新排序操做(由于事情发生在优化器不知道的另外一个线程中),则Volatile很是有用。 这是你如何增量的正交选择。

若是您想要阅读更多关于无锁代码的信息,以及正确的编写方法,这是一篇很是好的文章

http://www.ddj.com/hpc-high-performance-computing/210604448


#3楼

编辑:正如评论中所指出的,这些天我很乐意使用Interlocked来处理单个变量的状况 ,这显然是能够的。 当它变得更复杂时,我仍然会恢复锁定......

当您须要递增时,使用volatile将无济于事 - 由于读取和写入是单独的指令。 另外一个线程可能会在您阅读以后但在您回写以前更改该值。

就我我的而言,我几乎老是只是锁定 - 以一种明显正确的方式,比波动性或Interlocked.Increment更容易正确。 就我而言,无锁多线程是真正的线程专家,其中我不是一个。 若是Joe Duffy和他的团队构建了一个很好的库,这些库能够在没有像我构建的东西那么多锁定的状况下进行并行化,这很棒,并且我会在心跳中使用它 - 可是当我本身进行线程处理时,我会尝试把事情简单化。


#4楼

lock(...)有效,但可能阻塞一个线程,若是其余代码以不兼容的方式使用相同的锁,则可能致使死锁。

Interlocked。*是正确的方法...由于现代CPU支持它做为原语,因此开销要少得多。

挥发性自己是不正确的。 尝试检索而后写回修改值的线程仍然可能与执行相同操做的另外一个线程冲突。


#5楼

volatile ”不会取代Interlocked.Increment ! 它只是确保变量不缓存,而是直接使用。

增长变量实际上须要三个操做:

  1. 增量

Interlocked.Increment全部三个部分做为单个原子操做执行。

相关文章
相关标签/搜索