标准C ++ 11是否保证memory_order_seq_cst防止StoreLoad对原子周围的非原子重新排序? [英] Does standard C++11 guarantee that memory_order_seq_cst prevents StoreLoad reordering of non-atomic around an atomic?

查看:94
本文介绍了标准C ++ 11是否保证memory_order_seq_cst防止StoreLoad对原子周围的非原子重新排序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

标准C ++ 11是否保证memory_order_seq_cst防止StoreLoad在非原子内存访问的原子操作周围重新排序?

Does standard C++11 guarantee that memory_order_seq_cst prevents StoreLoad reordering around an atomic operation for non-atomic memory accesses?

众所周知,C ++ 11中有6个std::memory_order,并且它指定如何围绕原子操作对常规非原子存储进行排序-工作草案,标准适用于C ++ 2016-07-12编程语言: http ://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4606.pdf

As known, there are 6 std::memory_orders in C++11, and its specifies how regular, non-atomic memory accesses are to be ordered around an atomic operation - Working Draft, Standard for Programming Language C++ 2016-07-12: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4606.pdf

§29.3顺序和一致性

§ 29.3 Order and consistency

§29.3/1

枚举 memory_order 指定详细的常规 (非原子)内存的同步顺序(如1.10中所述),并且可能 提供操作订购.其枚举值及其 含义如下:

The enumeration memory_order specifies the detailed regular (non-atomic) memory synchronization order as defined in 1.10 and may provide for operation ordering. Its enumerated values and their meanings are as follows:

众所周知,这6个memory_order阻止了其中某些重新排序:

Also known, that these 6 memory_orders prevent some of these reordering:

但是,memory_order_seq_cst是否阻止针对常规,非原子的内存访问或仅针对具有相同memory_order_seq_cst的其他原子的原子操作围绕StoreLoad重新排序?

But, does memory_order_seq_cst prevent StoreLoad reordering around an atomic operation for regular, non-atomic memory accesses or only for other atomic with the same memory_order_seq_cst?

即为了防止这种StoreLoad重新排序,我们应该同时对STORE和LOAD使用std::memory_order_seq_cst还是仅对其中之一使用?

I.e. to prevent this StoreLoad-reordering should we use std::memory_order_seq_cst for both STORE and LOAD, or only for one of it?

std::atomic<int> a, b;
b.store(1, std::memory_order_seq_cst); // Sequential Consistency
a.load(std::memory_order_seq_cst); // Sequential Consistency


关于Acquire-Release语义非常清楚,它指定了跨原子操作的完全非原子的内存访问重新排序: http://en.cppreference.com/w/cpp/atomic/memory_order

为防止StoreLoad重新排序,我们应使用std::memory_order_seq_cst.

To prevent StoreLoad-reordering we should use std::memory_order_seq_cst.

两个例子:

  1. std::memory_order_seq_cst用于存储和加载:存在MFENCE
  1. std::memory_order_seq_cst for both STORE and LOAD: there is MFENCE

StoreLoad不能重新排序-GCC 6.1.0 x86_64: https://godbolt.org/g/mVZJs0

StoreLoad can't be reordered - GCC 6.1.0 x86_64: https://godbolt.org/g/mVZJs0

std::atomic<int> a, b;
b.store(1, std::memory_order_seq_cst); // can't be executed after LOAD
a.load(std::memory_order_seq_cst); // can't be executed before STORE

  1. std::memory_order_seq_cst仅用于LOAD:没有MFENCE
  1. std::memory_order_seq_cst for LOAD only: there isn't MFENCE

StoreLoad可以重新排序-GCC 6.1.0 x86_64: https://godbolt.org/g/2NLy12

StoreLoad can be reordered - GCC 6.1.0 x86_64: https://godbolt.org/g/2NLy12

std::atomic<int> a, b;
b.store(1, std::memory_order_release); // can be executed after LOAD
a.load(std::memory_order_seq_cst); // can be executed before STORE

如果C/C ++编译器使用了C/C ++ 11到x86的替代映射,则在LOAD:MFENCE,MOV (from memory)之前刷新了存储缓冲区,因此我们也必须对LOAD使用std::memory_order_seq_cst: http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html 由于此示例在方法(3)的另一个问题中进行了讨论:

Also if C/C++-compiler used alternative mapping of C/C++11 to x86, which flushes the Store Buffer before the LOAD: MFENCE,MOV (from memory), so we must use std::memory_order_seq_cst for LOAD too: http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html As this example is discussed in another question as approach (3): Does it make any sense instruction LFENCE in processors x86/x86_64?

即我们应该对存储和加载使用std::memory_order_seq_cst来保证生成MFENCE,以防止StoreLoad重新排序.

I.e. we should use std::memory_order_seq_cst for both STORE and LOAD to generate MFENCE guaranteed, that prevents StoreLoad reordering.

是真的,memory_order_seq_cst用于原子加载或存储:

Is it true, that memory_order_seq_cst for atomic Load or Store:

  • 特定获取发布语义-防止:针对常规,非原子内存访问,

,但防止StoreLoad在原子操作周围重新排序仅适用于其他具有相同memory_order_seq_cst?

but prevent StoreLoad reordering around an atomic operation only for other atomic operations with the same memory_order_seq_cst?

推荐答案

不,标准C ++ 11 保证memory_order_seq_cst阻止 StoreLoad non-atomic周围的non-atomic.

No, standard C++11 doesn't guarantee that memory_order_seq_cst prevents StoreLoad reordering of non-atomic around an atomic(seq_cst).

即使是标准C ++ 11,也不都不能保证memory_order_seq_cst阻止atomic(non-seq_cst)周围atomic(seq_cst) StoreLoad 重新排序.

Even standard C++11 doesn't guarantee that memory_order_seq_cst prevents StoreLoad reordering of atomic(non-seq_cst) around an atomic(seq_cst).

编程语言C ++标准工作草案2016-07-12: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4606.pdf

Working Draft, Standard for Programming Language C++ 2016-07-12: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4606.pdf

  • 所有memory_order_seq_cst操作上都应有一个总订单S-C ++ 11 Standard:
  • There shall be a single total order S on all memory_order_seq_cst operations - C++11 Standard:

§29.3

§ 29.3

3

所有memory_order_seq_cst上应有一个总订单S 操作,与之前发生"的命令一致,并且 所有受影响位置的修改订单,以便每个 memory_order_seq_cst操作B,该操作从原子加载值 对象M观察到以下值之一:...

There shall be a single total order S on all memory_order_seq_cst operations, consistent with the "happens before" order and modification orders for all affected locations, such that each memory_order_seq_cst operation B that loads a value from an atomic object M observes one of the following values: ...

  • 但是,任何原子顺序小于memory_order_seq_cst的原子操作都没有顺序一致性,也没有单一的总顺序,即非memory_order_seq_cst操作可以用memory_order_seq_cst操作在允许的方向上重新排序-C ++ 11标准:
    • But, any atomic operations with ordering weaker than memory_order_seq_cst hasn't sequential consistency and hasn't single total order, i.e. non-memory_order_seq_cst operations can be reordered with memory_order_seq_cst operations in allowed directions - C++11 Standard:
    • §29.3

      § 29.3

      8 [注意: memory_order_seq_cst确保顺序一致性 仅适用于没有数据争用并且专门使用的程序 memory_order_seq_cst操作.任何使用较弱的排序都会 除非使用了特别小心的措施,否则此保证将失效.特别是, memory_order_seq_cst栅栏确保仅针对栅栏的总订单 他们自己.栅栏通常不能用于恢复顺序 具有较弱订购规范的原子操作的一致性. —尾注]

      8 [ Note: memory_order_seq_cst ensures sequential consistency only for a program that is free of data races and uses exclusively memory_order_seq_cst operations. Any use of weaker ordering will invalidate this guarantee unless extreme care is used. In particular, memory_order_seq_cst fences ensure a total order only for the fences themselves. Fences cannot, in general, be used to restore sequential consistency for atomic operations with weaker ordering specifications. — end note ]


      C ++编译器也允许这样的重新排序:


      Also C++-compilers allows such reorderings:

      1. 在x86_64上

      通常-如果在编译器中将seq_cst实现为存储后的屏障,则:

      Usually - if in compilers seq_cst implemented as barrier after store, then:

      STORE-C(relaxed); LOAD-B(seq_cst);可以重新排序为LOAD-B(seq_cst); STORE-C(relaxed);

      STORE-C(relaxed); LOAD-B(seq_cst); can be reordered to LOAD-B(seq_cst); STORE-C(relaxed);

      由GCC 7.0 x86_64生成的Asm屏幕快照: https://godbolt.org/g/4yyeby

      Screenshot of Asm generated by GCC 7.0 x86_64: https://godbolt.org/g/4yyeby

      理论上也是可能的-如果在编译器中seq_cst在加载之前实现为屏障,则:

      Also, theoretically possible - if in compilers seq_cst implemented as barrier before load, then:

      STORE-A(seq_cst); LOAD-C(acq_rel);可以重新排序为LOAD-C(acq_rel); STORE-A(seq_cst);

      STORE-A(seq_cst); LOAD-C(acq_rel); can be reordered to LOAD-C(acq_rel); STORE-A(seq_cst);

      1. 在PowerPC上

      STORE-A(seq_cst); LOAD-C(relaxed);可以重新排序为LOAD-C(relaxed); STORE-A(seq_cst);

      STORE-A(seq_cst); LOAD-C(relaxed); can be reordered to LOAD-C(relaxed); STORE-A(seq_cst);

      在PowerPC上也可以这样重新排序:

      Also on PowerPC can be such reordering:

      STORE-A(seq_cst); STORE-C(relaxed);可以重新排序为STORE-C(relaxed); STORE-A(seq_cst);

      STORE-A(seq_cst); STORE-C(relaxed); can reordered to STORE-C(relaxed); STORE-A(seq_cst);

      如果甚至允许原子变量跨原子(seq_cst)重新排序,那么非原子变量也可以跨原子(seq_cst)重新排序.

      If even atomic variables are allowed to be reordered across atomic(seq_cst), then non-atomic variables can also be reordered across atomic(seq_cst).

      由GCC 4.8 PowerPC生成的Asm屏幕截图: https://godbolt.org/g/BTQBr8

      Screenshot of Asm generated by GCC 4.8 PowerPC: https://godbolt.org/g/BTQBr8

      更多详细信息:

      1. 在x86_64上

      STORE-C(release); LOAD-B(seq_cst);可以重新排序为LOAD-B(seq_cst); STORE-C(release);

      STORE-C(release); LOAD-B(seq_cst); can be reordered to LOAD-B(seq_cst); STORE-C(release);

      英特尔®64和IA-32架构

      8.2.3.4可能会将早期商店中的货物重新排序到不同的位置

      8.2.3.4 Loads May Be Reordered with Earlier Stores to Different Locations

      即x86_64代码:

      STORE-A(seq_cst);
      STORE-C(release); 
      LOAD-B(seq_cst);
      

      可以重新排序为:

      STORE-A(seq_cst);
      LOAD-B(seq_cst);
      STORE-C(release); 
      

      之所以会发生这种情况,是因为c.storeb.load之间不是mfence:

      This can happen because between c.store and b.load isn't mfence:

      x86_64-GCC 7.0 : https://godbolt.org/g/dRGTaO

      C ++和asm-代码:

      C++ & asm - code:

      #include <atomic>
      
      // Atomic load-store
      void test() {
          std::atomic<int> a, b, c;
          a.store(2, std::memory_order_seq_cst);          // movl 2,[a]; mfence;
          c.store(4, std::memory_order_release);          // movl 4,[c];
          int tmp = b.load(std::memory_order_seq_cst);    // movl [b],[tmp];
      }
      

      它可以重新排序为:

      #include <atomic>
      
      // Atomic load-store
      void test() {
          std::atomic<int> a, b, c;
          a.store(2, std::memory_order_seq_cst);          // movl 2,[a]; mfence;
          int tmp = b.load(std::memory_order_seq_cst);    // movl [b],[tmp];
          c.store(4, std::memory_order_release);          // movl 4,[c];
      }
      


      此外,可以通过四种方式实现x86/x86_64中的顺序一致性:

      1. LOAD(无围栏)和STORE + MFENCE
      2. LOAD(无围栏)和LOCK XCHG
      3. MFENCE + LOADSTORE(无围栏)
      4. LOCK XADD(0)和STORE(无围栏)
      1. LOAD (without fence) and STORE + MFENCE
      2. LOAD (without fence) and LOCK XCHG
      3. MFENCE + LOAD and STORE (without fence)
      4. LOCK XADD ( 0 ) and STORE (without fence)

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆