我正在尝试理解C#Volatile类。
正如我读到的那样:
Volatile.Write
方法强制写入位置中的值
在通话时。此外,任何早期的程序
加载和存储必须在调用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);
}
}
在开始写入Volatile.Write(ref m_flag, 1);
之前,cpu会等待m_flag
之前的命令吗?
这有助于线程同步吗?
答案 0 :(得分:6)
Eeeh,有点儿。更好的说法是:保证,如果任何其他线程将cpu将在Volatile.Write之前等待命令(ref m_flag,1);在开始写入m_flag之前?
m_flag
设置为1,他们也会将m_value
设置为5。
这有助于线程同步吗?
我不会说它有助于同步 - 但它确实有助于实现正确性。
如果您没有使用易失性读/写,则编译器/运行时/ cpu可能会对Thread1
方法中的两条指令重新排序,并且程序将能够打印0, 5或根本没有。
使用易失性读/写,程序将打印5或根本不打印,但从不 0.这是预期的行为。
答案 1 :(得分:3)
这对线程同步有何帮助?
在设置命令执行顺序的意义上,它无助于线程同步。它允许您确保并发线程以特定顺序观察内存中值的更改,以防特定顺序对程序逻辑很重要。
[开始写入
Volatile.Write(ref m_flag, 1);
之前,CPU是否等待m_flag
之前的命令?
不,写入m_value
的命令已经执行。但是,它的结果可能在CPU核心外部不可见 - 特别是,在写入{{1}的命令之后,在不同核心上运行的线程可能会从m_value
读取旧值它已经完成执行。这是因为新值可能位于CPU的缓存中,而不是存储在内存中。
如果你写
5
而不是m_value = 5;
m_flag = 1;
其他核心可能会以不同的顺序看到写入:首先它会看到Volatile.Write(ref m_flag, 1)
变为m_flag
,之后会看到1
}成了m_value
。如果您的其他主题使用5
的值来判断m_flag
的有效性,则逻辑可能会被破坏:例如,m_value
可能偶尔会打印零。