对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_?

这对线程同步有何帮助?

对Volatile的理解.读/写

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可能偶尔会打印零。