代码之家  ›  专栏  ›  技术社区  ›  Gilgamesz

在C++中用内存屏障防止超薄空气值

  •  1
  • Gilgamesz  · 技术社区  · 7 年前

    下面让我们考虑C++中的两个线程并发程序:

    x,y 是全球性的, r1,r2 是本地线程, store load int 是原子的。 内存模型=C++ 11

    int x = 0, int y = 0
    r1 = x   | r2 = y 
    y = r1   | x = r2
    

    允许编译器将其编译为:

    int x = 0, int y = 0
    r1 = x   | r2 = 42 
    y = r1   | x = r2
             | if(y != 42) 
             |    x = r2 = y    
    

    而且,虽然它是线程内一致的,但它可能会导致不确定的结果,因为执行该程序可能会导致 (x, y) = (42, 42)

    它被称为 稀薄的空气 价值观问题。它是存在的,我们必须忍受它。

    我的问题是:内存屏障是否会阻止编译器进行导致空气不足的疯狂优化?

    例如:

    [fence] = atomic_thread_fence(memory_order_seq_cst);
    
    int x = 0, int y = 0
    r1 = x   | r2 = y 
    [fence]  | [fence]
    y = r1   | x = r2
    
    2 回复  |  直到 7 年前
        1
  •  1
  •   Peter Cordes    7 年前

    x y atomic

    volatile int




    atomic_int x = 0, y = 0
    r1 = x.load(mo_relaxed)    | r2 = y.load(mo_relaxed)
     y.store(r1, mo_relaxed)   | x.store(r2, mo_relaxed)
    

    r2

    r2 = y.load(mo_relaxed);
    if (r2 == 42) {                   // control dependency, not a data dependency
        x.store(42, mo_relaxed);
    } else {
        x.store(r2, mo_relaxed);
    }
    

    x = 42;

    42 y.load

    mo_consume

        2
  •  0
  •   davmac    7 年前

      (Thread #1)       |   (Thread #2)
    r1 = x              |
    [fence]             |
    y = junk temporary  |
                        | r2 = y    // junk!
                        | [fence]
                        | x = r2
    y = r1              |
    

    std::atomic_int x = 0, y = 0;
    int r1 = x;    |    int r2 = y;
    y = r1;        |    x = r2;