0

我有两个 pthreads 正在读取/写入共享内存位置。在一个线程中,我不断检查内存位置的更新。(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() 究竟做了什么?

编辑 1:我理解为什么更新可能不会立即可见。我的问题特别是为什么即使在很长一段时间后也看不到它。

4

1 回答 1

1

您遇到了一个直到最近才在 C/C++ 中标准化的领域——内存模型。

底线是,在没有同步的情况下(从广义上讲),无法保证一个线程所做的更改何时或什至是否会被另一个线程看到。

它不仅仅是什么时候(或是否)某些东西会变得可见——它也会影响排序。因此,例如,这种事情是完全不安全的:

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
}

因为从线程 2 的角度来看,在线程 1 的写入从该线程的角度可见之前,它很可能important_data_ready成为。更糟糕的是,由于缺乏关于这应该如何工作的标准化,编译器和 CPU 之间的细节有所不同。trueimportant_data

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

您正在使用的__sync_synchronize函数是一个遗留的 gcc 工具,它发出一个完整的内存屏障——简而言之,这确保了线程在内存屏障之前所做的一切在内存屏障之后所做的任何事情之前对另一个线程都是可见的。但是你并没有安全地使用它——它还需要被阅读线程使用以确保完全安全。

如果可以的话,使用 C11 支持的新标准化机制可能会更好。Herb Sutter 的这次演讲是一个很好的起点。

于 2014-05-06T09:36:57.287 回答