为什么readonly和volatile修饰符是互斥的?

时间:2008-12-28 16:55:17

标签: c# .net multithreading readonly volatile

我有一个引用类型变量readonly,因为引用永远不会改变,只有它的属性。当我尝试向其添加volatile修饰符时,编译警告我不会让两个修饰符都应用于同一个变量。但我认为我需要它是易变的,因为我不想在阅读其属性时遇到缓存问题。我错过了什么吗?或编译器错了?

更新正如Martin在以下评论中所述:在参考类型对象的情况下,readonly和volatile修饰符仅适用于引用,而不适用于对象的属性。这就是我所缺少的,所以编译器是正确的。

class C
{
    readonly volatile string s;  // error CS0678: 'C.s': a field cannot be both volatile and readonly
}

3 个答案:

答案 0 :(得分:15)

readonlyvolatile修饰符都不是渗透性的。它们适用于引用本身,而不是对象的属性。

readonly关键字断言 - 并强制执行 - 变量在初始化后无法更改。变量是存储引用的小块内存。

volatile关键字告诉编译器多个线程可能会更改变量的内容。这可以防止编译器使用优化(例如将变量的值读入寄存器并在多个指令上使用该值),这可能会导致并发访问问题。同样,这只会影响存储引用的小块内存。

以这种方式应用,您可以看到它们确实是互斥的。如果某些内容是只读的(只能在初始化或构造时写入一次),那么它也不能是易失性的(可以由多个线程随时写入)。


至于您对缓存问题的关注,IIRC,关于何时编译器可以缓存属性调用的结果,有相当严格的规则。请记住, 是一个方法调用,并且它是一个非常重的优化(从编译器的立场)来缓存它的值并跳过再次调用它。我不认为你需要过多地关注自己。

答案 1 :(得分:1)

只能在首次构造对象时写入只读字段。因此,CPU上不会出现任何缓存问题,因为该字段是不可变的,并且不可能更改。

答案 2 :(得分:0)

虽然引用本身可能是线程安全的,但它的属性可能不是。想想如果两个线程试图同时遍历你的引用对象中的列表会发生什么。