C# 4 in a Nutshell(强烈推荐顺便说一句)使用以下代码来演示 MemoryBarrier 的概念(假设 A 和 B 在不同的线程上运行):
class Foo{
int _answer;
bool complete;
void A(){
_answer = 123;
Thread.MemoryBarrier(); // Barrier 1
_complete = true;
Thread.MemoryBarrier(); // Barrier 2
}
void B(){
Thread.MemoryBarrier(); // Barrier 3;
if(_complete){
Thread.MemoryBarrier(); // Barrier 4;
Console.WriteLine(_answer);
}
}
}
他们提到障碍 1 和 4 阻止此示例写入 0,障碍 2 和 3 提供新鲜度保证:他们确保如果 B 在 A 之后运行,读取_complete将评估为true。
我真的不明白。我想我理解为什么需要设置障碍 1 和 4:我们不希望对_answer的写入进行优化并放置在写入_complete之后(障碍 1),我们需要确保_answer没有被缓存(障碍 4) . 我也认为我理解为什么需要屏障 3:如果 A 运行到刚刚写入_complete = true之后,B 仍然需要刷新_complete才能读取正确的值。
我不明白为什么我们需要屏障 2!我的一部分说这是因为线程 2(运行 B)可能已经运行到(但不包括)if(_complete),所以我们需要确保_complete被刷新。
但是,我不明白这有什么帮助。_complete是否仍然有可能在 A 中设置为 true ,但 B 方法会看到_complete的缓存(错误)版本?即,如果线程 2 运行方法 B 直到第一个 MemoryBarrier 之后,然后线程 1 运行方法 A 直到_complete = true但没有进一步,然后线程 1 恢复并测试if(_complete) -如果不导致false吗?