什么时候不应该使用[[carry_dependency]]?

时间:2013-11-21 16:47:19

标签: c++ c++11 concurrency carries-dependency

我发现问题(例如this one)询问[[carries_dependency]]做了什么,而这不是我在这里问的问题。

我想知道你什么时候不应该使用它,因为我读过的答案都让你听起来像是可以在任何地方涂抹这些代码,而且你会得到相同或更快的代码。一条评论说代码可以相同或更慢,但海报没有详细说明。

我认为使用它的适当位置是在任何functon返回或参数上,它是一个指针或引用,它将在调用线程中传递或返回,并且不应该在回调或线程入口点上使用。< / p>

有人可以对我的理解发表评论,并详细说明一般情况,何时何时不使用它?

编辑:如果有其他读者感兴趣的话,我知道这个主题有this本书。它可能包含我的答案,但我还没有机会阅读它。

2 个答案:

答案 0 :(得分:2)

  

因为我已阅读所有答案,听起来像可以抹灰   此代码无处不在,而且您会神奇地得到等于或更快的代码

获得更快的代码的唯一方法是当该注释允许省略围栏时。

因此唯一可能有用的唯一情况是:

  • 您的程序在重要的频繁执行代码中对原子加载操作使用消耗排序;
  • “消费价值”不仅可以立即在本地使用,还可以传递给其他功能;
  • 目标CPU为使用操作提供了特定的保证(与该操作之前的给定篱笆一样强大,仅用于该操作);
  • 编译器作者认真对待他们的工作:他们设法将消耗某种语言的高级语言转换为消耗CPU的水平,以便从CPU保证中受益。

这是可能获得可测量的更快代码的一堆必要条件。

(C ++社区的最新趋势是放弃发明一种在所有情况下都是安全的适当的编译方案,并为用户提供一种完全不同的方式来指示用户指示编译器生成“使用”值的代码,具有更清晰,天真可转换的C ++代码。)

  

有评论说代码可以相等或更慢,但是张贴者   没有详细说明。

当然,您可以随意地将它们放在程序中的那种注释通常不能使代码更有效!那太容易了,而且也自相矛盾。

任一某些注释在您的代码上指定了一个约束,这是对编译器的承诺,并且您不能将其放置在任何与之不符的地方。保证代码中的内容(例如C ++中的noexcept,C中的restrict),否则会以各种方式破坏代码(noexcept函数中的异常会停止程序,并限制指针的别名可能会导致有趣的错误编译和不良行为(这种情况下以前没有定义行为);然后编译器可以使用它以特定方式优化代码。

或者,该注释不会以任何方式限制代码,并且编译器无法依靠任何东西,并且注释不会再产生任何优化机会

如果您在某些情况下获得了更高效的代码,而又没有用注释破坏程序的代价,那么在其他情况下,您就可能必须获得效率更低的代码。通常,这是正确的,对于consume语义尤其如此。 ,这将先前描述的内容限制在C ++构造的翻译中。

  

我想在任何函数返回或   作为指针或引用的参数,将被传递或   在调用线程中返回

不,唯一有用的情况是 ,当预期的调用函数可能使用消耗内存的顺序时。

答案 1 :(得分:2)

在现代C ++中,通常根本不应该使用std::memory_order_consume[[carries_dependency]]。在委员会提出一种更好的机制以便编译器可以实际实现的机制时,基本上已弃用它们。

希望这不需要在各处撒满[[carries_dependency]]kill_dependency

  

2016-06 P0371R1: Temporarily discourage memory_order_consume

     

被广泛接受的是,该标准中当前的memory_order_consume定义没有用。 当前所有的编译器基本上都将其映射到memory_order_acquire。困难似乎既来自于实现的复杂性,也归因于当前定义使用相当笼统的“ dependency”定义,因此需要频繁且不便使用kill_dependency调用,并且经常需要[[carries_dependency]]批注。细节可以在例如P0098R0

值得注意的是,在C ++中,x - x仍然具有依赖关系,但是大多数编译器自然会打破依赖关系,并用常量0替换该表达式。但是,如果编译器可以证明分支后的值范围方面的信息,有时也会将数据依赖项转换为控件依赖项。


在仅将mo_consume提升为mo_acquire的现代编译器上,总是可以进行完全积极的优化;即使在使用 [[carries_dependency]]的代码中,kill_dependencymo_consume都没有任何收益,更不用说其他代码了。


mo_acquire的这种增强对于诸如POWER和ARM之类的弱顺序ISA上的RCU等实际用例而言,具有潜在的显着性能成本(额外的障碍)。观看Paul E. McKenney的CppCon 2015演讲C++ Atomics: The Sad Story of memory_order_consume的视频。 (链接包括摘要)。

如果要获得真正的依存关系排序只读性能,则必须“自己滚动”,例如通过使用mo_relaxed并检查asm以验证是否已将其编译为具有依赖项的asm。 (避免对这样的值做任何“怪异”的操作,例如将其传递给各个函数。)DEC Alpha基本上已经死了,并且其他所有ISA在asm中都提供了无障碍的依赖顺序,只要asm本身具有 data 依赖性。

如果您不想自己动手,过着危险的生活,那么在可以正常工作的“简单”用例中继续使用mo_consume可能不会有什么伤害;也许将来的某些mo_consume实现将具有相同的名称,并且以与C ++ 11兼容的方式工作。


正在制作新的consume,例如2018年的http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0750r1.html