为什么我需要同步障碍?

时间:2014-05-05 21:50:08

标签: gcc parallel-processing pthreads memory-barriers memory-fences

我有两个正在读/写共享内存位置的pthread。在一个线程中,我一直在检查内存位置的更新。 (Linux,Glibc)

主题1:

while(1) {
    if (ptr)
        ptr->do_something();
}

主题2:

ptr = update();

这里的要点是,即使过了一段时间,我也看不到更新。如果我按如下方式使用同步屏障,则立即可以看到更新:

    while(1) {

    __sync_synchronize();
    if (ptr)
        ptr->do_something();
    }

所以我的问题是:

  1. 为什么即使在很长一段时间后仍无法看到更新?
  2. __sync_synchronize()究竟做了什么?
  3. 编辑1:我理解为什么更新可能不会立即显示。我的问题特别是为什么即使在很长一段时间后它也不可见。

1 个答案:

答案 0 :(得分:1)

直到最近 - 你的内存模型还没有被C / C ++标准化的区域弄错了。

最重要的是,在没有同步的情况下(广义上来说), no 保证关于何时,或者即使一个线程所做的更改被另一个线程看到线程。

还有更多的东西,而不仅仅是(或者如果)某些东西会变得可见 - 它也会影响排序。所以这种事情是完全不安全的:

bool important_data_ready = false;

// In thread 1
void* important_data = calculate_important_data();
important_data_ready = true;

// In thread 2
if (important_data_ready) {
  // use important_data
}

因为从线程1的角度看,important_data_ready很可能从线程2的角度来看成为true,所以从该线程的角度来看,线程1对important_data的写入是可见的。更糟糕的是,如果没有关于如何工作的标准化,编制者和CPU之间的细节会有所不同。

自Java 5(2004)以来,这些东西已在Java中标准化,但在C11和C ++ 11中仅在C / C ++中标准化。

你正在使用的__sync_synchronize函数是一个传统的gcc工具,它会发出一个完整的内存障碍 - 简而言之,这可以确保线程在该内存屏障之前所做的一切都可以在任何事情之前被另一个线程看到在记忆障碍之后完成。但是你没有安全地使用它 - 读取线程也需要使用它才能完全安全。

如果可以的话,你可能会更好,使用C11支持的新标准化机制。 This talk by Herb Sutter是一个很好的起点。