对 Volatile.Read/Write 的理解
Posted
技术标签:
【中文标题】对 Volatile.Read/Write 的理解【英文标题】:understanding of Volatile.Read/Write 【发布时间】:2014-08-10 00:29:57 【问题描述】:我正在尝试理解 C# Volatile 类。
如我所见:
Volatile.Write
方法强制写入 location 中的值
到通话点。此外,任何早期的程序顺序
加载和存储必须在调用 Volatile.Write 之前发生。
Volatile.Read
方法强制读取位置中的值
在通话点。此外,任何以后的程序顺序加载
并且存储必须在调用 Volatile.Read 之后发生。
这是否意味着在以下情况下:
internal sealed class ThreadsSharingData
private Int32 m_flag = 0;
private Int32 m_value = 0;
// This method is executed by one thread
public void Thread1()
// Note: 5 must be written to m_value before 1 is written to m_flag
m_value = 5;
Volatile.Write(ref m_flag, 1);
// This method is executed by another thread
public void Thread2()
// Note: m_value must be read after m_flag is read
if (Volatile.Read(ref m_flag) == 1)
Console.WriteLine(m_value);
cpu 会等待Volatile.Write(ref m_flag, 1);
之前的命令,然后再开始写入m_flag
?
这对线程同步有何帮助?
【问题讨论】:
它仅与内存模型较弱的处理器相关,即获取和释放语义很重要的处理器。除了ARM内核之外,剩下的很少。它不是正确同步的替代品,编写没有同步的线程安全代码是一个非常先进的概念。否则,this question 已经很好地涵盖了。 【参考方案1】:cpu 将等待 Volatile.Write(ref m_flag, 1); 之前的命令在开始写入 m_flag 之前?
哎呀,有点。更好的表达方式是:可以保证,如果任何其他线程看到 m_flag
设置为 1,他们也会看到 m_value
设置为 5。
这对线程同步有何帮助?
我不会说它有助于同步 - 但它确实有助于实现正确性。
如果您不使用 volatile 读取/写入,编译器/运行时/cpu 可能会重新排序 Thread1
方法中的两条指令,并且程序将能够打印 0、5 或什么都没有。
使用易失性读/写,程序将打印 5 或根本不打印,但从不 0。这是预期的行为。
【讨论】:
【参考方案2】:这对线程同步有何帮助?
从设置命令执行顺序的意义上说,它无助于线程同步。它使您可以确保并发线程以特定顺序观察内存中值的更改,以防特定顺序对您的程序逻辑很重要。
[是否] CPU 在开始写入
m_flag
之前等待Volatile.Write(ref m_flag, 1);
之前的命令?
不,写入m_value
的命令已经执行。但是,它的结果可能在 CPU 内核之外不可见 - 特别是,运行在不同内核上的线程可能会从 m_value
读取旧值 在向其写入 5
的命令之后执行完毕。这是因为新值可能在 CPU 的缓存中,而不是在内存中。
如果你写
m_value = 5;
m_flag = 1;
而不是Volatile.Write(ref m_flag, 1)
,另一个核心可能会以不同的顺序看到写入:首先它会看到m_flag
变成1
,然后它会看到m_value
变成5
。如果你的其他线程使用m_flag
的值来判断m_value
的有效性,那么逻辑可能会被破坏:例如Thread2
可能偶尔会打印零。
【讨论】:
以上是关于对 Volatile.Read/Write 的理解的主要内容,如果未能解决你的问题,请参考以下文章