Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 间接访问是否需要volatile?_C#_Multithreading_Volatile - Fatal编程技术网

C# 间接访问是否需要volatile?

C# 间接访问是否需要volatile?,c#,multithreading,volatile,C#,Multithreading,Volatile,请注意,我不是要用其他方法(如锁)替换volatile,我是在问volatile的性质——因此我在意义上使用了“needed”、volatile或novolatile 考虑这样的情况,一个线程只向变量x(Int32)写入数据,而另一个线程只读取数据。这两种情况下的访问都是直接的 需要volatile来避免缓存,对吗 但是如果对x的访问是间接的,例如通过属性: int x; int access_x { get { return x; } set { x = value; } } 因此,这两个

请注意,我不是要用其他方法(如锁)替换
volatile
,我是在问
volatile
的性质——因此我在意义上使用了“needed”、
volatile
或no
volatile

考虑这样的情况,一个线程只向变量
x
Int32
)写入数据,而另一个线程只读取数据。这两种情况下的访问都是直接的

需要
volatile
来避免缓存,对吗

但是如果对
x
的访问是间接的,例如通过属性:

int x;
int access_x { get { return x; } set { x = value; } } 
因此,这两个线程现在只使用
access\ux
,而不是
x
x
是否需要标记为
volatile
?如果是,当不再需要
volatile
时,是否存在间接限制

Update:考虑读者的这种代码(不写):

在第二个
if
中,编译器可以使用旧值进行计算,因为
x
可以在缓存中,并且没有
volatile
无需重新蚀刻。我的问题是关于这种变化:

if (access_x>10)
   ...   
// second thread changes `x`
if (access_x>10)
  ...
假设我跳过了
volatile
x
。会发生什么/会发生什么

x
是否需要标记为
volatile

是的,也不是(但大多是肯定的)

“是的”,因为从技术上讲,你在这里没有保证。编译器(C#和JIT)可以进行他们认为合适的任何优化,只要优化在单个线程中执行时不会改变代码的行为。一个明显的优化是省略对属性setter和getter的调用,直接访问字段(即内联)。当然,编译器可以做任何它想做的分析和进一步的优化

“不”,因为在实践中这通常不是问题。使用方法包装访问,C#编译器不会优化字段,JIT编译器也不太可能这样做(即使方法是内联的……同样,没有保证,但如果没有执行这样的优化,我认为未来的版本也不太可能)。因此,您只剩下内存一致性问题(另一个原因是使用了
volatile
,即基本上处理在硬件级别执行的优化)

只要代码只在与英特尔x86兼容的硬件上运行,该硬件就会将所有读写操作视为不稳定的

但是,其他平台可能不同。安腾和ARM是两个具有不同内存模型的常见示例

就我个人而言,我更喜欢写技术细节。尽管缺乏保证,但编写恰好可以工作的代码只是为了在将来找个时间让代码因为某种神秘的原因停止工作

因此,我认为您真的应该将字段标记为
volatile

如果是,当不再需要volatile时,是否存在间接限制

否。如果存在这样的限制,则必须将其记录在案才能发挥作用。实际上,编译器优化的限制实际上只是“间接层次”(正如您所说的)。但是,任何级别的间接寻址都无法避免硬件级别的优化,甚至编译器优化方面的限制也严格“在实践中”。您无法保证编译器永远不会对任何任意深度的调用进行更深入的代码分析和更积极的优化


更一般地说,我的经验法则是:如果我试图决定是否应该使用一些我知道通常用于防止并发相关场景中的bug的特定功能,我必须问“我真的需要这个功能吗,或者没有它代码可以正常工作吗?”,那么,我可能对该功能的工作方式了解不够,无法安全地避免使用它


将其视为旧版本的一个变体,“如果你必须询问它的成本,你就买不起。”

你通常不想从volatile开始使用它。属性在这种情况下不会更改任何内容。添加属性不会使读/写操作变为“间接”。它只是更改与
x
相关的代码部分。换句话说,如果没有属性,您将收到一个陈旧值
x
,那么属性getter中的代码也将收到一个陈旧值
x
@Rob,谢谢,但我不理解您的第一句话。假设我写
x=7
。这是直接任务。当我调用
setFoo()
它调用
setBar()
它调用
setMe()
它调用
setX()
它调用property setter时,我会说有很多间接操作。那么,既然这些都是伪装的方法,为什么你不把属性算作间接寻址呢?@astrowalker这是多层次的间接寻址,只有当你从
setFoo
的角度来看它的时候。从
setX
的角度来看,没有间接性
setX
直接修改
x
。没有理由说,
setFoo
setX
更重要,getter可以内联到调用方,并最终“直接”引用
x
。由于您似乎关心无锁设计,因此您应该真正了解Linux内核的文档,并了解可能出现错误的情况。谢谢你,我不是在找什么肮脏的把戏来做记录,我想有更好的理解。我在“安全第一”营地:-。
if (access_x>10)
   ...   
// second thread changes `x`
if (access_x>10)
  ...