简体   繁体   English

C++11 原子:std::memory_order 代码是否可移植?

[英]C++11 atomic: is std::memory_order code portable?

In functions like std::atomic::compare_exchange , there's runtime parameters like std::memory_order_release , std::memory_order_relaxed .在像std::atomic::compare_exchange这样的函数中,有像std::memory_order_releasestd::memory_order_relaxed这样的运行时参数。 (http://en.cppreference.com/w/cpp/atomic/atomic/compare_exchange ) http://en.cppreference.com/w/cpp/atomic/atomic/compare_exchange

I'm not sure is these memory order flags are guaranteed to exist in all kinds of CPU/architects, if some CPU don't support a flag, does this flag lead to crash or?我不确定这些内存顺序标志是否保证存在于所有类型的 CPU/架构师中,如果某些 CPU 不支持某个标志,该标志会导致崩溃还是? Seems some of these flags are designed for intel Itanium, etc, not sure if std::memory_order related code is portable or not.似乎其中一些标志是为英特尔安腾等设计的,不确定与std::memory_order相关的代码是否可移植。

Would you give some suggestions?你能给一些建议吗?

In general, compilers are free to only provide the strongest memory guarantees regardless of what you ask for.通常,无论您要求什么,编译器都可以自由地仅提供最强的内存保证。

On some platforms, there are relaxed guarantees that are sufficient.在某些平台上,有足够的宽松保证。 Not all platforms support these relaxed guarantees.并非所有平台都支持这些宽松的保证。 On those platforms, compilers must provide strictly stronger guarantees.在这些平台上,编译器必须提供更严格的保证。

So they are portable, in that comforming compilers must provide that guarantee or better when you ask for a paticular guarantee.因此它们是可移植的,因为当您要求特定保证时,符合标准的编译器必须提供该保证或更好

Note that it isn't just the hardware that is of concern.请注意,值得关注的不仅仅是硬件。 Certain optimizations and reorderings may be legal or not depending on what memory order guarantee you ask for.某些优化和重新排序可能合法与否,取决于您要求的内存顺序保证。 I am unaware of any compiler that relies on that, but I am not a compiler expert.我不知道任何依赖于此的编译器,但我不是编译器专家。

The C++ standard does have the concept of so-called "freestanding" implementations, which can support a subset of the standard library. C++ 标准确实有所谓的“独立”实现的概念,它可以支持标准库的一个子集。 However, it also defines bare-minimum functionality that even a freestanding implementation must support.但是,它还定义了即使是独立的实现也必须支持的最低限度的功能。 Within that list is the entirety of the <atomic> header.在该列表中是整个<atomic>标头。

So yes, implementations must support these.所以是的,实现必须支持这些。

However, that doesn't mean that a particular flag will do exactly and only what that flag describes.但是,这并不意味着特定标志将完全执行且仅执行该标志所描述的操作。 The flags represent the minimum memory barrier, the specific things that are guaranteed to be visible.标志代表最小内存屏障,保证可见的特定事物。 The implementation could issue a full memory barrier even for flags that don't require it, if the hardware implementation doesn't have lower-tier memory barriers.如果硬件实现没有较低层的内存屏障,即使对于不需要它的标志,实现也可能会发出完整的内存屏障。

So you should write code against what the standard says, and let the compiler sort out the details.所以你应该按照标准写代码,让编译器整理出细节。 If it proves to be inefficient on a platform, you can inspect the assembly to see if you might be able to improve matters.如果证明它在平台上效率低下,您可以检查组件以查看是否可以改进问题。

But to answer your main question, yes, atomic-based code is portable (modulo compiler bugs).但是要回答您的主要问题,是的,基于原子的代码是可移植的(模编译器错误)。

In practice, consume semantic is always strengthened to acquire by current compilers because it turned out to be very hard to implement safely without doing that.在实践中,消费语义总是被当前的编译器加强以获取,因为事实证明如果不这样做就很难安全地实现。 Either:要么:

  • the architecture provides acquire on all loads, and then load consume does the same thing as load acquire which does the same as load relaxed: nothing special (like x86);该架构在所有负载上提供获取,然后负载消耗与负载获取执行相同的操作,与负载放松相同:没什么特别的(如 x86);
  • the architecture requires an acquire barrier even on dependent accesses (very very rare, maybe only DEC Alpha): then the compiler will use an acquire barrier on consume;该架构甚至在依赖访问时也需要获取屏障(非常非常罕见,可能只有 DEC Alpha):然后编译器将在消费时使用获取屏障;
  • The ISA guarantees dependency ordering for loads in asm, but full acquire needs a barrier. ISA 保证了 asm 中加载的依赖顺序,但完全获取需要一个屏障。 (This is what consume is trying to expose to the programmer). (这就是consume试图向程序员公开的内容)。 The compiler should provide you the benefit of avoiding the barrier with logical (not crazy) uses of consume编译器应该为您提供避免逻辑(不是疯狂)使用消费障碍的好处

    • either the compiler tries to do that, but it's tricky and fails in some corner cases that the compiler back end optimizations break (the front end often does not communicate with its back end enough to avoid these just for consume);要么编译器尝试这样做,但它很棘手并且在编译器后端优化中断的某些极端情况下失败(前端通常不会与其后端进行足够的通信,以避免这些只是为了消费);
    • or you don't trust the compiler, set optimization to zero, which doesn't even guarantee that no trivial optimization done implicitly by the back end will break consume (and make performance very bad);或者您不信任编译器,将优化设置为零,这甚至不能保证后端隐式完成的任何微不足道的优化都不会破坏消耗(并使性能变得非常糟糕);
    • or the compiler writers did not care about efficiency or knew they couldn't do a reliable job providing consume so they provide acquire instead, which is semantically correct but really less efficient, and not the intent of the standard.或者编译器作者不关心效率,或者知道他们无法提供可靠的工作,因此他们提供了获取,这在语义上是正确的但实际上效率较低,而不是标准的意图。

(And C++'s consume semantic is crazy. It's one of the most inconsistent part of C++ which tells you a lot.) (而且 C++ 的消费语义很疯狂。它是 C++ 中最不一致的部分之一,它告诉了你很多。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM