9

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

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

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

3 回答 3

16

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

readonly关键字断言(并强制)变量初始化后不能更改。变量是存储引用的一小块内存。

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

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


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

于 2008-12-28T17:22:47.323 回答
1

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

于 2008-12-28T17:02:36.257 回答
0

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

于 2008-12-28T17:08:46.337 回答