一般情况下,我们需要使用内存屏障(防止编译器或CPU重新排序内存访问)来保证多线程同步,例如:
int x = 0;
int y = 0;
void thread1(void)
{
x = 1;
atomic_store_explicit(&y, 1, memory_order_release);
}
void thread2(void)
{
int tmp_y = atomic_load_explicit(&y, memory_order_acquire);
int tmp_x = x;
if (tmp_y)
assert(tmp_x); // must be ok
}
但是有一种情况我不确定是否需要内存屏障,这个很难描述。请参考代码:
int x = 0;
int *px = NULL;
void thread1(void)
{
x = 1;
atomic_store_explicit(&px, &x, memory_order_release);
}
void thread2(void)
{
int *p = atomic_load_explicit(&px, memory_order_relaxed); // Do we need memory_order_acquire here?
if (p)
assert(*p); // is it ok?
}
或者另一个例子:
int x = 0;
int y = 0;
int *pv = &y;
void thread1(void)
{
x = 1;
atomic_store_explicit(&pv, &x, memory_order_release);
}
void thread2(void)
{
int *p = atomic_load_explicit(&pv, memory_order_relaxed); // Do we need memory_order_acquire here?
int val = *p;
if (p == &x)
assert(val); // is it ok?
}
原子对象上的释放操作只会对与同一原子对象或获取线程栅栏上的获取操作相关的内存排序产生任何影响。
如果
px
/pv
上没有获取操作或获取线程栅栏,则程序与使用宽松排序而不是释放排序完全相同。
因此,两个示例中
*p
的负载都是数据竞争,并且具有未定义的行为。