与使用Interlocked类相比,使用volatile关键字有什么好处吗?

cod*_*nix 8 .net c# multithreading volatile interlocked

换句话说,我可以使用常规变量和Interlocked类无法解决的volatile变量吗?

Abe*_*bel 17

编辑:问题很大程度上改写

要回答这个问题,我在这个问题上跌一点,并发现了几件事情volatileInterlocked我是不知道的.让我们明白这一点,不仅仅是为了我,而是为了这次讨论和其他人阅读:

  • volatile读/写应该不受重新排序的影响.这不仅意味着阅读和写作,但这并不意味着其他任何行动;
  • 不强制在CPU上进行波动,即硬件级别(x86在任何读/写时使用获取和释放围栏).它确实阻止了编译器或CLR优化;
  • Interlocked使用原子汇编指令进行CompareExchange(cmpxchg),Increment(inc)等;
  • Interlocked 有时使用锁:多处理器系统上硬件锁 ; 在单处理器系统中,没有硬件锁;
  • Interlocked不同之处volatile在于它使用了一个完整的栅栏,其中volatile使用半栅栏.
  • 写入后的读取可以在您使用时重新排序volatile.它不可能发生Interlocked.VolatileRead并且VolatileWrite具有与`volatile相同的重新排序问题(链接感谢Brian Gideon).

现在我们已经有了规则,我们可以为您的问题定义答案:

  • 从技术上讲:是的,你可以做些与volatile你无关的事情Interlocked:
    1. 语法:你不能写a = b在哪里a或是b不稳定的,但这很明显;
    2. 由于重新排序,您可以在将其写入volatile变量后读取不同的值.你不能这样做Interlocked.换句话说:你可以用安全的volatile,那么你可以与Interlocked.
    3. 表现:volatile比那更快Interlocked.
  • 语义上:不,Interlocked因为它只提供操作的超集并且使用起来更安全,因为它应用了完整的防护.你不能做任何事情volatile,你不能用做Interlocked,你可以做很多Interlocked你不能使用挥发性做:

    static volatile int x = 0;
    x++;                        // non-atomic
    static int y = 0;
    Interlocked.Increment(y);   // atomic
    
    Run Code Online (Sandbox Code Playgroud)
  • 范围:是的,声明变量volatile使每次访问都变得不稳定.不可能以任何其他方式强制这种行为,因此volatile不能被替换Interlocked.在其他库,接口或硬件可以访问您的变量并随时更新它或需要最新版本的情况下,需要这样做.

如果您问我,最后一点是实际需要,volatile并且可能使两个进程共享内存并且无需锁定即可读取或写入.volatile在此上下文中声明变量更安全,然后强制所有程序员使用Interlocked(编译器无法强制使用).


编辑:以下引用是我原来答案的一部分,我会把它留在;-)

引用C#编程语言标准:

对于非易失性字段,考虑重新排序指令的优化技术可能导致多线程程序中的意外和不可预测的结果,这些程序访问没有同步的字段,例如lock-statement提供的字段.这些优化可以由编译器,运行时系统或硬件执行.对于易失性字段,此类重新排序优化受到限制:

  • 读取volatile字段称为volatile读取.易失性读取具有:获取语义";也就是说,它保证在指令序列之后发生的对内存的任何引用之前发生.

  • 写入易失性字段称为易失性写入.易失性写入具有"释放语义"; 也就是说,保证在指令序列中的写指令之前的任何存储器引用之后发生.

更新:问题在很大程度上被重写,纠正了我的原始回复并添加了"真实"答案