有人能很好地解释一下c#中的volatile关键字吗?它能解决哪些问题,不能解决哪些问题?在哪些情况下,它将节省我使用锁定?
当前回答
我发现Joydip Kanjilal的这篇文章非常有用!
当您将一个对象或变量标记为volatile时,它将成为volatile读写的候选对象。需要注意的是,在c#中,所有的内存写操作都是volatile的,不管你写的是volatile对象还是非volatile对象。但是,当读取数据时,就会出现这种不确定性。当读取非易失性数据时,执行线程可能总是获得最新的值,也可能不总是。如果对象是volatile,线程总是获得最新的值
我就把它放在这里,供大家参考
其他回答
综上所述,这个问题的正确答案是: 如果代码在2.0运行时或更高版本中运行,volatile关键字几乎不需要,如果不必要地使用,弊大于利。也就是说,永远不要用它。但是在运行时的早期版本中,需要对静态字段进行适当的双重检查锁定。特别是具有静态类初始化代码的静态字段。
CLR喜欢优化指令,所以当你在代码中访问一个字段时,它可能并不总是访问该字段的当前值(它可能来自堆栈等)。将字段标记为volatile可以确保该指令可以访问该字段的当前值。当程序中的并发线程或操作系统中运行的其他代码可以修改该值(在非锁定场景中)时,这很有用。
您显然失去了一些优化,但它确实使代码更加简单。
只需查看volatile关键字的官方页面,您就可以看到典型用法的示例。
public class Worker
{
public void DoWork()
{
bool work = false;
while (!_shouldStop)
{
work = !work; // simulate some work
}
Console.WriteLine("Worker thread: terminating gracefully.");
}
public void RequestStop()
{
_shouldStop = true;
}
private volatile bool _shouldStop;
}
将volatile修饰符添加到_shouldStop的声明中,您将总是得到相同的结果。但是,如果_shouldStop成员上没有这个修饰符,行为是不可预测的。
所以这绝对不是完全疯狂的事情。
存在缓存一致性,负责CPU缓存的一致性。
如果CPU采用强内存模型(如x86)
因此,volatile字段的读写在x86上不需要特殊的指令:普通的读写(例如,使用MOV指令)就足够了。
示例来自c# 5.0规范(第10.5.3章)
using System;
using System.Threading;
class Test
{
public static int result;
public static volatile bool finished;
static void Thread2() {
result = 143;
finished = true;
}
static void Main() {
finished = false;
new Thread(new ThreadStart(Thread2)).Start();
for (;;) {
if (finished) {
Console.WriteLine("result = {0}", result);
return;
}
}
}
}
产生输出:result = 143
如果finished字段没有被声明为volatile,那么在store to finished之后,允许主线程可以看到store to result,因此主线程可以从字段结果中读取值0。
Volatile行为依赖于平台,所以你应该在需要的时候考虑使用Volatile,以确保它能满足你的需求。
即使是volatile也不能阻止(所有类型的)重排序(c# - c#内存模型的理论与实践,第2部分)
尽管对A的写操作是不稳定的,从A_Won的读操作也是不稳定的,但栅栏都是单向的,实际上允许这种重新排序。
所以我相信,如果你想知道什么时候使用volatile (vs lock vs Interlocked),你应该熟悉内存围栏(full, half)和同步的需求。那为了你自己,你自己去找答案吧。
我发现Joydip Kanjilal的这篇文章非常有用!
当您将一个对象或变量标记为volatile时,它将成为volatile读写的候选对象。需要注意的是,在c#中,所有的内存写操作都是volatile的,不管你写的是volatile对象还是非volatile对象。但是,当读取数据时,就会出现这种不确定性。当读取非易失性数据时,执行线程可能总是获得最新的值,也可能不总是。如果对象是volatile,线程总是获得最新的值
我就把它放在这里,供大家参考
从MSDN: volatile修饰符通常用于由多个线程访问而不使用lock语句序列化访问的字段。使用volatile修饰符可确保一个线程检索到另一个线程写入的最新值。
推荐文章
- 实体框架核心:在上一个操作完成之前,在此上下文中开始的第二个操作
- 如何为构造函数定制Visual Studio的私有字段生成快捷方式?
- 如何使用JSON确保字符串是有效的JSON。网
- AppSettings从.config文件中获取值
- 通过HttpClient向REST API发布一个空体
- 如何检查IEnumerable是否为空或空?
- 自动化invokerrequired代码模式
- 在c#代码中设置WPF文本框的背景颜色
- 在c#中,什么是单子?
- c#和Java中的泛型有什么不同?和模板在c++ ?
- c#线程安全快速(est)计数器
- 如何将此foreach代码转换为Parallel.ForEach?
- 如何分裂()一个分隔字符串到一个列表<字符串>
- 如何转换列表<字符串>列表<int>?
- c#对象列表,我如何得到一个属性的和