说明C#中volatile关键字的用法

Rom*_*ier 87 .net c# volatile

我想编写一个程序,它可以直观地说明volatile关键字的行为.理想情况下,它应该是一个程序,它执行对非易失性静态字段的并发访问,并因此而获得不正确的行为.

在同一程序中添加volatile关键字应该可以解决问题.

那是我无法实现的.即使尝试多次,启用优化等,我总是会在没有'volatile'关键字的情况下获得正确的行为.

你对这个话题有什么看法吗?你知道如何在一个简单的演示应用程序中模拟这样的问题吗?它取决于硬件吗?

小智 101

我已经实现了一个有效的例子!

从wiki收到的主要想法,但对C#进行了一些更改.维基文章为C++的静态字段演示了这一点,它看起来像C#总是小心地将请求编译到静态字段......我用非静态字段做例子:

如果您在发布模式下运行此示例并且没有调试器(即使用Ctrl + F5),则该行将while (test.foo != 255)优化为"while(true)"并且此程序永远不会返回.但是在添加volatile关键字之后,您总能获得"确定".

class Test
{
    /*volatile*/ int foo;

    static void Main()
    {
        var test = new Test();

        new Thread(delegate() { Thread.Sleep(500); test.foo = 255; }).Start();

        while (test.foo != 255) ;
        Console.WriteLine("OK");
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 在.NET 4.0上测试,x86和x64都可以确认该示例仍然适用.谢谢!:) (5认同)
  • 只是为了明确,你要将"volatile"关键字添加到foo的声明中,对吧? (3认同)

Cra*_*ntz 21

是的,它依赖于硬件(如果没有多个处理器,你不太可能看到问题),但它也依赖于实现.CLR规范中的内存模型规范允许Microsoft实现CLR不一定要做的事情.我在volatile关键字上看到的最好的文档是Joe Duffy的博客文章.请注意,他说MSDN文档"极具误导性".

  • http://igoro.com/archive/volatile-keyword-in-c-memory-model-explained/ (8认同)

Ray*_*yes 6

当没有指定'volatile'关键字时,发生错误并不是真正的问题,更多的是当未指定错误时可能发生错误.一般来说,你会知道什么时候比编译器更好!

最简单的思考方式是编译器可以,如果需要,可以内联某些值.通过将值标记为volatile,您告诉自己和编译器该值可能实际发生更改(即使编译器不这么认为).这意味着编译器不应该内联值,保持缓存或提前读取值(尝试优化).

此行为与C++中的关键字实际上不是同一个关键字.

MSDN 在这里有一个简短的描述.这可能是关于波动率,原子性和联锁主题的更深入的帖子