C ++内存订购一致性

时间:2012-09-17 00:26:02

标签: c++ memory c++11 garbage-collection

假设我有以下代码:

void* p0 = nullptr;
void* p1 = alloc_some_data();
void f1() {
    p0 = p1;
    p1 = nullptr;
}

假设{1}在线程1上运行。是否有可能(保留代码)另一个线程可能在某个时刻将f1p0视为{{1} (如果编译器或硬件重新排序指令,如第二次赋值发生在第一次之前)?

我问这个的原因是因为我想实现一个垃圾收集器,我想知道我是否需要使用原子指令(p1)从GC线程访问指针。如果GC线程看到nullptr没有问题,但是如果GC线程看到std::atomic则会出现问题,因为它会先前在p1中将数据报告为无法访问时显而易见。

3 个答案:

答案 0 :(得分:2)

如果您在一个线程中读取一个由另一个线程写入而没有同步的对象,则会有数据争用。这显然意味着您的垃圾收集器需要使用某种同步来读取值。关于你的原始问题:你的代码中没有任何内容表明在p0的写入之前写入p1变得可见,即另一个线程确实可以看到两者都为空。这与用于与另一个线程通信的同步原语无关:这两个写操作之间没有排序。

答案 1 :(得分:0)

是。虽然不一定可能,但完全有可能,因为这些操作不是原子的。

一个(少数可能的情况)是:

Thread 2: Get value of p0 (null)

Thread 1: Get value of p1 (non-null)
          p0 = p1
          p1 = nullptr

Thread 2: Get value of p1 (null)

您需要使用某种形式的访问控制(互斥锁)。

答案 2 :(得分:0)

您的问题的答案是肯定的,但它依赖于编译器和CPU。我想你还需要让p0p1变得不稳定。要停止重新排序,您可以使用_mm_sfence_mm_lfence instrinsics(适用于x86 / x64)