【发布时间】:2010-11-05 03:39:12
【问题描述】:
C#中volatile关键字的作用是什么?
我需要在哪里使用这个关键字?
我看到了下面的语句,但我无法理解为什么这里需要volatile?
internal volatile string UserName;
【问题讨论】:
标签: c# multithreading volatile
C#中volatile关键字的作用是什么?
我需要在哪里使用这个关键字?
我看到了下面的语句,但我无法理解为什么这里需要volatile?
internal volatile string UserName;
【问题讨论】:
标签: c# multithreading volatile
请参阅规范的第 10.5.3 节,其中指出:
对于非易失性字段,优化 重新排序指令的技术 可能导致意想不到的和 不可预知的结果 访问的多线程程序 没有同步的字段,例如 由 lock-statement 提供的 (第 8.12 节)。这些优化可以 由编译器执行,由 运行时系统,或由硬件。为了 volatile 字段,例如重新排序 优化受到限制:
一个 读取 volatile 字段称为 易失性读取。易失性读取具有 “获取语义”;也就是说,它是 保证在任何之前发生 对之后发生的内存的引用 它在指令序列中。
一个 写易失性字段称为 易失性写入。易失性写入具有 “释放语义”;也就是说,它是 保证在任何记忆之后发生 写之前的参考 指令中的指令 顺序。
这些限制确保 所有线程都会观察到 volatile 由任何其他线程执行的写入 按照它们的顺序 执行。符合要求的实现 不需要提供一个单一的 易失性写入的总排序为 从所有执行线程中看到。
仔细阅读,如果你有任何打算制作一个 volatile 字段。如果您没有完全彻底地了解 volatile 语义的所有含义,请不要尝试使用它们。使用锁通常要好得多,它会自动为您提供足够的内存屏障以确保必要的获取和释放语义。请记住,锁只有在被竞争时才真正昂贵。
【讨论】:
Volatile 用于在代码运行时无需您进行任何操作即可更改的变量。它告诉编译器编写程序集时不要缓存变量,而是确保在每次使用前读取它。
易失性的一个例子是硬件寄存器,您的代码已映射内存并正在读取该寄存器以确定何时设置标志。硬件可能会在您的代码运行时设置该值,如果不使用 volatile 关键字,您不会注意到此更改,因为程序集实际上不会检查该值。
【讨论】:
Volatile 是对编译器(和 ngen/jit 编译器)的提示,该变量的值可以随时更改,因此通过在本地缓存 volatile 值来访问变量的优化被禁用。
考虑以下代码:
If (UserName == "")
// do something
If (UserName == "Fred")
// do something
如果 volatile 不存在,编译器可能会生成 IL,它将引用存储在堆栈中以进行第一次比较,然后将其重用于第二次比较。但是,添加 volatile 会告诉编译器该引用可能被另一个线程更改,从而强制它生成不会重用第一次比较的堆栈副本的 IL。
【讨论】:
MSDN 会比我总结的更好......
" volatile 关键字表示一个字段可能被同时执行的多个线程修改。声明为 volatile 的字段不受编译器优化的影响,假设由单个线程访问。这确保了最多-to-date 值始终存在于该字段中。”
http://msdn.microsoft.com/en-us/library/x13ttww7(v=VS.100).aspx
【讨论】:
表示该值可能被不同的线程更改,因此即使之前的指令已经读取了该值,也需要读取该值。
http://msdn.microsoft.com/en-us/library/x13ttww7%28VS.71%29.aspx
【讨论】:
只是告诉编译器这个变量 将随时通过任何方式改变其价值,并且 编译器不应该对这个变量做任何假设。
通常编译器会假设某个变量是 在运行时保持不变。这可能会导致检查错误 寄存器值重复。因为寄存器值可能 被任何东西改变。所以对于这些变量 应声明为“易失性”,并且每次都进行检查 在没有任何假设的情况下出现在代码中。
【讨论】: