我一直在阅读 Joe Duffy 关于并发编程的书。我有一个关于无锁线程的学术问题。
首先:我知道无锁线程充满了危险(如果你不相信我,请阅读书中关于内存模型的部分)
不过,我有一个问题: 假设我有一个带有 int 属性的类。
这个属性引用的值会被多个线程非常频繁地读取
值发生变化的情况极为罕见,当发生变化时,将由单个线程进行更改。
如果它确实发生了变化,而另一个使用它的操作正在运行中,没有人会失去一根手指(任何人使用它所做的第一件事就是将它复制到局部变量)
我可以使用锁(或 readerwriterlockslim 来保持读取并发)。 我可以将变量标记为 volatile(很多例子都是这样做的)
但是,即使是 volatile 也会对性能造成影响。
如果我在 VolatileWrite 发生变化时使用它,并保持读取访问正常,会怎样?像这样:
public class MyClass
{
private int _TheProperty;
internal int TheProperty
{
get { return _TheProperty; }
set { System.Threading.Thread.VolatileWrite(ref _TheProperty, value); }
}
}
我不认为我会在现实生活中尝试这个,但我很好奇答案(最重要的是,作为我是否理解我一直在阅读的内存模型内容的检查点)。
最佳答案
将变量标记为“volatile”有两个作用。
1) 读写具有acquire和release语义,因此其他内存位置的读写不会相对于该内存位置的读写“时间上前后移动”。 (这是一个简化,但你明白我的意思。)
2) 抖动产生的代码不会“缓存”一个看似逻辑上不变的值。
前一点是否与您的场景相关,我不知道;您只描述了一个内存位置。仅具有 volatile 写入而没有 volatile 读取是否重要由您决定。
但在我看来,后一点非常相关。如果您在非 volatile 变量上有自旋锁:
while(this.prop == 0) {}
抖动有权生成这段代码,就像你写的一样
if (this.prop == 0) { while (true) {} }
它是否真的这样做了,我不知道,但它有权这样做。如果您想要代码在每次循环时实际重新检查属性,将其标记为易变是正确的方法。
关于c# - 我可以避免对很少更改的变量使用锁吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2158001/