对Volatile的理解.读/写
本文关键字:Volatile | 更新日期: 2023-09-27 18:09:15
我正在努力理解C#易失性类。
正如我读到的:
-
Volatile.Write
方法强制写入位置中的值到呼叫点。此外,任何早期的程序顺序加载和存储必须在调用Volatile之前进行。写 -
Volatile.Read
方法强制从中读取位置中的值在通话时。此外,任何以后的程序顺序都会加载并且存储必须发生在对Volatile的调用之后。阅读
这意味着在的情况下
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将在CCD_ 3之前等待命令,然后开始写入CCD_?
这对线程同步有何帮助?
cpu将在Volatile之前等待命令。写入(ref m_flag,1(;在开始写入m_flag之前?
嗯,有点。一个更好的表达方式是:可以保证,如果任何其他线程看到m_flag
设置为1,他们也会看到m_value
设置为5。
这对线程同步有何帮助?
我不会说它有助于同步,但它确实有助于实现正确性。
如果不使用volatile读/写,编译器/运行时/cpu可能会对Thread1
方法中的两条指令进行重新排序,并且程序将能够打印0、5或什么都不打印。
使用volatile读/写,程序将打印5或什么都不打印,但永远不会0。这就是预期行为。
这对线程同步有什么帮助?
从设置线程命令执行顺序的意义上讲,它对线程同步没有帮助。它可以确保并发线程以特定的顺序观察内存中值的变化,在特定的顺序对程序逻辑很重要的情况下。
CPU是否在开始写入
m_flag
之前等待Volatile.Write(ref m_flag, 1);
之前的命令?
否,写入m_value
的命令已经执行。然而,它的结果在CPU内核之外可能是不可见的——特别是,在向其写入5
的命令执行完毕后,在不同内核上运行的线程可能会从m_value
读取旧值。这是因为新值可能在CPU的缓存中,而不是在内存中。
如果你写
m_value = 5;
m_flag = 1;
而不是Volatile.Write(ref m_flag, 1)
,另一个核心可能会以不同的顺序看到写入:首先,它会看到m_flag
变成1
,然后,它会发现m_value
变成5
。如果您的另一个线程使用m_flag
的值来判断m_value
的有效性,则逻辑可能会被破坏:例如,Thread2
可能偶尔会打印零。