c# - .net 4.0 中引用类型的 volatile

标签 c# .net volatile

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

据我所知,对于原始类型,volatile 可以立即反射(reflect)来自另一个线程的值变化。对于引用类型,它可以立即反射(reflect)地址的变化。但是,对象的内容呢。它们是否仍在缓存中?

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

例如,我有:

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

}

如果一个线程调用函数AddValue,列表的地址没有改变,另一个线程是否会更新列表的“内容”变化,或者可以为每个线程缓存内容它不会为其他线程更新吗?

最佳答案

I understand that for primitive type, volatile can reflect value changes from another thread immediately

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

首先,要清楚 volatile 影响变量,而不是

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

第三,volatile 并不意味着来自其他线程的值变化立即可见。 Volatile 意味着变量具有获取和释放语义。 Volatile 会影响从特定线程中观察到内存突变副作用发生的顺序。存在一致的通用突变顺序并且可以从所有线程即时观察到该顺序中的那些突变的想法并不是内存模型做出的保证。

However, what about the content of the object?

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

If one thread calls the function AddValue, the address of list does not change, will another thread get updated about the "content" change of the list.

没有。为什么会这样?另一个线程可能位于不同的处理器上,并且该处理器缓存可能已经预加载了包含支持列表的数组地址的页面。改变列表可能会改变包含数组地址的存储位置,以引用一些完全不同的位置。

当然,列表类从一开始就不是线程安全的。如果您没有锁定对列表的访问权限,那么当您尝试执行此操作时,列表可能会崩溃并死亡。

你不需要 volatile;您需要的是在对列表的访问周围放置线程锁。由于线程锁会导致全栅栏,因此您不需要由 volatile 引入的半栅栏。

关于c# - .net 4.0 中引用类型的 volatile,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8662436/

相关文章:

c# - 在 C# 中将 UTC 日期时间转换为本地日期时间

.net - DateTimeOffsetAdapter干扰DateTimeOffset对象的WCF序列化

c++ - 通过 volatile 引用/指针访问声明的非 volatile 对象是否赋予所述访问 volatile 规则?

java - 再次设置 AtomicBoolean

c# - 没有背景点击事件的网格

c# - 在方法中传递对派生对象的引用时出错

.net - 在不使用 msiexec 的情况下从命令行卸载 MSI 文件

windows-7 - 设置多个环境变量

c++ - volatile 成员变量

c# - 解构赋值 - C# 中变量的对象属性