volatile作为同步机制

时间:2011-05-10 16:39:10

标签: c# multithreading synchronization

假设我有一个类Foo,它有一个名为Count的静态成员变量(类型为整数)。此变量用于多线程应用程序,我在对此变量进行任何读/写操作之前使用锁同步机制。在我阅读本文Volatile时,我得到的印象是我可以删除围绕此变量的所有锁定,并在声明此变量时使用volatile关键字。这应该照顾所有与synchnronization相关的东西。它是否正确?这种方法的优点和缺点是什么?

3 个答案:

答案 0 :(得分:8)

  

我可以删除这个变量周围的所有锁,只需在声明此变量时使用volatile关键字。这应该照顾所有与synchnronization相关的东西。它是否正确?

也许。也许不吧。获取多线程代码非常困难。获得低锁多线程代码最好留给专家。

  

这种方法的优点和缺点是什么?

优点是它可以快几毫秒来避免锁定。缺点是,如果你的低锁编程错误,那么你的程序看起来很好,然后有奇怪的故障模式,无法调试或重现。

当您的性能分析导致您断定低锁定解决方案是唯一方式来实现客户要求您达到的性能目标时,您应该只使用低锁定解决方案。当你对彻底的深入了解每个优化时,你应该只使用低锁解决方案,你的程序将运行的每个可能的CPU都可以执行低-开锁密码。您需要深入了解CLR保证的内存模型,硬件保证的内容以及所有差异。

我自己并不具备这种理解。这就是为什么除了最琐碎的低锁代码之外我什么也写不出来的东西,而且我还有行业领先专家认真阅读过的低锁代码。

答案 1 :(得分:4)

如果你所做的只是从多个线程读取该变量并从一个线程写入它,那么volatile可能会起作用。但是如果你在多个线程上更新值(即递增它),那么你需要某种同步。

例如,如果你写的是:

Count = Count + 1;

请记住,增量需要三个操作:读取,增量,写入。在多个线程上,您可能会遇到问题。想象一下Count的初始值为零。

  • 线程1读取Count(值0)
  • 线程2读取Count(值0)
  • 线程1递增其值(1)
  • 线程1写入Count(值1)
  • 线程2递增其值(1)
  • 线程2写入Count(值1)

Count的最终值为1,应为2。

您想要查看Interlocked课程。特别是Interlocked.IncrementInterlocked.CompareExchange

答案 2 :(得分:1)

volatile关键字与lock完全不同。 lock意味着需要将多个语句作为具有一致状态的单个工作单元进行,例如,如果您希望确保在您使用时没有其他线程可以添加或删除集合中的项目从集合中访问特定项目或计算集合中的项目。 volatile关键字会影响编译器在从源代码生成机器指令时尝试优化代码时的行为方式。编译器可能会以不影响该代码块的方式对特定代码块中的语句进行重新排序,但如果可以从另一个线程更改变量的值,则重新排序可能无效。使用volatile告诉编译器不要考虑这样的优化,并始终从内存中读取变量的值,而不是从缓存的寄存器中读取。

Jon Skeet在他的文章Volatility, Atomicity and Interlocking中更详细地讨论了这一点。