6

首先,我试图找出 using 是否Interlocked仍然需要volatile字段定义,这是我真正的问题。

但。由于懒得分析生成的 MSIL,我决定在实践中检查它。

我正在尝试使用MSDN 示例,以便volatile在代码应该在发布版本中中断并进行优化时使用。什么都没有。代码工作正常(在这种情况下 - 主线程优雅地终止),优化开启和关闭。

  1. volatile当我从一个线程使用Interlocked并从另一个没有锁的线程读取时,我是否仍然需要在字段上使用关键字?
  2. 来自第一个问题的代码的简单示例在哪里volatile有区别?
  3. 为什么当我删除volatile关键字并内置发布时,MSDN 示例仍然有效?

用于说明问题 1 的代码片段。

class Example
{
    volatile int val;

    void Do()
    {
        Task.Run(() => { while (val == 0) Console.WriteLine("running"); });

        Thread.Sleep(1000);
        Interlocked.Increment(ref val);
        Console.WriteLine("done.");
        Console.ReadLine();
    }
}
4

2 回答 2

2

如果变量未标记为volatile,则读取它的代码无法知道它可能被其他线程修改。所以 JIT 编译器不会知道将值保存在寄存器中可能是不安全的。

volatile是告诉 JIT 编译器其他线程可以修改该值的方式。更改值时其他线程可能使用Interlocked的无关紧要,因为 JITer 甚至可能不知道其他代码存在!

可能是您的简单示例有效,因为 JIT 编译器可以看到所有代码。如果这两个代码位在不同的方法甚至完全不同的程序集中,情况可能会有很大不同。

于 2013-02-04T17:12:42.400 回答
2

好吧,我设法生成了volatile确实有所作为Interlocked但无济于事的代码。您应该在没有调试器的情况下运行发布版本来测试它。

public class Example
{
    private volatile int val = 0;

    public static void Main()
    {
        var example = new Example();

        Task.Run(() => Interlocked.Increment(ref example.val));

        while (example.val == 0) ;
        // this never happens if val is not volatile
        Console.WriteLine("done.");
        Console.ReadLine();
    }
}

如果没有更详细的信息,我将接受@JimMischel 的回答,因为它有一些解释。

更新:还发现这篇博客文章解释了一些细节。

于 2013-02-04T17:42:37.120 回答