3

假设我有以下代码:

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

假设f1在线程 1 上运行。是否有可能(让代码保持原样)另一个线程可能在某个时候看到p0p1nullptr如果编译器或硬件重新排序指令,例如第二个赋值发生在第一个之前)?

我问这个的原因是因为我想实现一个垃圾收集器,我想知道我是否需要使用原子指令(std::atomic)从 GC 线程访问指针。如果 GC 线程看到了没有问题,p0 == p1 == alloc_some_data()但是如果 GC 线程看到了就会有问题,p0 == p1 == nullptr因为当它明显可以访问时,它会将先前在 p1 中的数据报告为不可访问。

4

3 回答 3

2

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

于 2012-09-17T00:33:33.240 回答
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)

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

于 2012-09-17T00:35:53.783 回答
0

您的问题的答案是肯定的,但它取决于编译器和 CPU。我认为你还需要制作p0p1挥发。要停止重新排序,您可以使用_mm_sfence_mm_lfenceinstrinsics(对于 x86/x64)

于 2012-09-17T00:37:57.177 回答