你是对的,内存屏障不能确保读取看到最新的值。它所做的是在单个线程上和线程之间强制执行操作之间的排序。
例如,如果线程 A 执行一系列存储,然后在最终存储到标志位置之前执行释放屏障,线程 B 从标志位置读取,然后在读取其他值之前执行获取屏障,那么其他变量将具有线程 A 存储的值:
// initially x=y=z=flag=0
// thread A
x=1;
y=2;
z=3;
release_barrier();
flag=1;
// thread B
while(flag==0) ; // loop until flag is 1
acquire_barrier();
assert(x==1); // asserts will not fire
assert(y==2);
assert(z==3);
当然,您需要确保加载和存储flag
是原子的(如果变量适当对齐,那么简单的加载和存储指令在大多数常见的 CPU 上都是如此)。如果没有线程 B 上的 while 循环,线程 B 很可能会为 读取一个陈旧的值 (0) flag
,因此您无法保证为其他变量读取的任何值。
因此,栅栏可用于在 Dekker 算法中强制同步。
这是 C++ 中的示例实现(使用 C++0x 原子变量):
std::atomic<bool> flag0(false),flag1(false);
std::atomic<int> turn(0);
void p0()
{
flag0.store(true,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
while (flag1.load(std::memory_order_relaxed))
{
if (turn.load(std::memory_order_relaxed) != 0)
{
flag0.store(false,std::memory_order_relaxed);
while (turn.load(std::memory_order_relaxed) != 0)
{
}
flag0.store(true,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
}
}
std::atomic_thread_fence(std::memory_order_acquire);
// critical section
turn.store(1,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_release);
flag0.store(false,std::memory_order_relaxed);
}
void p1()
{
flag1.store(true,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
while (flag0.load(std::memory_order_relaxed))
{
if (turn.load(std::memory_order_relaxed) != 1)
{
flag1.store(false,std::memory_order_relaxed);
while (turn.load(std::memory_order_relaxed) != 1)
{
}
flag1.store(true,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
}
}
std::atomic_thread_fence(std::memory_order_acquire);
// critical section
turn.store(0,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_release);
flag1.store(false,std::memory_order_relaxed);
}
有关完整分析,请参阅我在http://www.justsoftwaresolutions.co.uk/threading/implementing_dekkers_algorithm_with_fences.html上的博客条目