C# .net 4.0中引用类型的volatile

C# .net 4.0中引用类型的volatile,c#,.net,volatile,C#,.net,Volatile,我对引用类型的volatile感到困惑 我知道对于基元类型,volatile可以立即反映来自另一个线程的值更改。对于引用类型,它可以立即反映地址更改。但是,对象的内容如何呢。它们还在缓存吗 (假设List.Add()是一个原子操作) 例如,我有: class A { volatile List<String> list; void AddValue() { list.Add("a value"); } } A类 { 易变列表

我对引用类型的
volatile
感到困惑

我知道对于基元类型,
volatile
可以立即反映来自另一个线程的值更改。对于引用类型,它可以立即反映地址更改。但是,对象的内容如何呢。它们还在缓存吗

(假设
List.Add()
是一个原子操作)

例如,我有:

class A
{
     volatile List<String> list;
     void AddValue()
     {
        list.Add("a value");
     }

}
A类
{
易变列表;
void AddValue()
{
列表。添加(“a值”);
}
}

如果一个线程调用函数
AddValue
,列表的地址不会更改,另一个线程是否会更新列表的“内容”更改,或者每个线程的内容都会被缓存,而其他线程不会更新?

关键字
volatile
对列表的内容没有影响(或者更准确地说,是被引用的对象)

谈论另一个线程的更新/未更新是对正在发生的事情的过分简化。您应该使用
lock
语句来同步对共享列表的访问。否则,您实际上会面临可能导致程序崩溃的争用条件。
list
类本身不是线程安全的。

比那更糟

如果您同时访问一个非线程安全的对象,您的程序实际上可能会崩溃。获取过期信息并不是最糟糕的潜在结果

在线程之间共享.NET基类库对象时,除了使用锁定,您别无选择。对于无锁编程,您需要在最低级别对数据结构进行侵入性更改

我知道对于基元类型,volatile可以立即反映来自另一个线程的值更改

您至少在三个方面理解不正确。在深入了解弱内存模型、获取和释放语义以及它们如何影响您的程序之前,不应尝试使用volatile

首先,要明确volatile影响变量,而不是值

其次,volatile对包含值类型值的变量的影响与对包含引用的变量的影响没有任何不同

第三,volatile并不意味着其他线程的值更改立即可见。volatile意味着变量具有获取和释放语义。volatile影响从特定线程观察到的内存突变副作用的发生顺序。存在一致性宇宙的想法l突变的顺序,以及在所有线程中可以即时观察到这些顺序的突变,并不是记忆模型的保证

但是,对象的内容如何

怎么办?引用类型的易失性变量引用的存储位置不需要具有任何特定的线程特征

如果一个线程调用函数AddValue,列表的地址不变,那么另一个线程将更新列表的“内容”更改

没有。为什么会这样?其他线程可能位于不同的处理器上,并且处理器缓存可能预加载了包含支持列表的阵列地址的页面。更改列表可能会将包含阵列地址的存储位置更改为引用某个完全不同的位置

当然,列表类首先不是线程安全的。如果您没有锁定对列表的访问,那么当您尝试这样做时,列表可能会崩溃并死亡

您不需要volatile;您需要的是在访问列表的周围放置线程锁。因为线程锁会导致完全隔离,所以您不需要volatile引入的半隔离。

了解volatile的实际作用以及它如何影响字段的良好解释


该站点上的整个线程部分都是必须阅读的,它包含了大量有用的信息,在我设计多线程软件时,这些信息对我来说非常有用。

我不确定这一点,但我猜,鉴于该列表实际上只是一个指针(地址),当内容得到更新时,它会立即反映到所有地方,因为内容将驻留在堆中,然而,随着地址的更改,堆栈会发生更改,我认为这可以驻留在单个核心上。但是,正如所说,没有专家。这只是一个猜测。另外,顺便说一句。大量优化的反复无常。大量优化。这是非常重要的一些人建议不要使用volatile修饰符,而是在需要时使用volatireRead和volatireWrite(在系统命名空间中的类上找到的一些全局静态方法,可能可以在google上找到)@Alxandr:小心。Volatile read和Volatile write是调用的潜在昂贵方法,它们会导致完全隔离,而不是人们所期望的半隔离。如果您出于性能原因编写无锁代码(还有什么其他原因会让您这么做呢?)完全有可能VolatileRead和VolatileWrite更糟糕。您必须仔细分析它。volatile修饰符会导致对字段的所有、是的所有读写进行volatile读写,但使用volatile读写是可选的。另外,afaik,volatile读写总是比lockin快至少10个数量级g、 它在任何方面都不起同样的作用。至少这是我在.NET线程上的视频告诉我的(我想是在lidnug上找到的)。现在去找一个视频,解释你不同意谁/与谁争论……:)非常感谢Eric。根据我对你解释的理解,volatile用于防止记忆突变的副作用。但是,什么是用来防止CPU寄存器复制内存值的。在多核CPU中,两个多核缓存变量的两个副本(例如