volatile,Interlocked:试图破坏代码
本文关键字:代码 Interlocked volatile | 更新日期: 2023-09-27 17:57:49
首先,我试图了解使用Interlocked
是否仍然需要volatile
字段定义,这是我真正的问题。
但是。由于懒得分析生成的MSIL,我决定在实践中进行检查。
我正在尝试MSDN示例中volatile
的使用,当代码应该在带有优化的版本构建中中断时。什么也没坏。通过打开和关闭优化,代码运行良好(在这种情况下,主线程正常终止)
- 当我使用
Interlocked
从一个线程向字段写入并在没有锁的情况下从另一个线程读取时,我是否仍然需要字段上的volatile
关键字 - 来自第1个问题的代码的简单示例
volatile
在哪里起作用 - 当我删除
volatile
关键字并在发行版中构建时,为什么MSDN示例仍然有效
用于说明问题1的代码片段。
class Example
{
volatile int val;
void Do()
{
Task.Run(() => { while (val == 0) Console.WriteLine("running"); });
Thread.Sleep(1000);
Interlocked.Increment(ref val);
Console.WriteLine("done.");
Console.ReadLine();
}
}
如果变量没有标记为volatile
,那么读取它的代码就无法知道它可能会被其他线程修改。所以JIT编译器不会知道将值保存在寄存器中可能是不安全的。
volatile
是告诉JIT编译器其他线程可以修改该值的方式。其他线程在更改值时可能使用Interlocked
是无关紧要的,因为JITer甚至可能不知道其他代码的存在!
您的简单示例之所以有效,可能是因为JIT编译器可以看到所有代码。如果这两个代码位在不同的方法中,甚至完全在不同的程序集中,情况可能会大不相同。
好吧,我成功地生成了volatile
确实有影响,而Interlocked
没有帮助的代码。您应该在没有调试器的情况下运行版本构建来测试它。
public class Example
{
private volatile int val = 0;
public static void Main()
{
var example = new Example();
Task.Run(() => Interlocked.Increment(ref example.val));
while (example.val == 0) ;
// this never happens if val is not volatile
Console.WriteLine("done.");
Console.ReadLine();
}
}
如果没有更详细的解释,我会接受@JimMischel的回答,因为它有一些解释。
更新:还发现这篇博客文章解释了一些细节。