【问题标题】:GCC's behaviour with std::async(std::launch::async) vs. Clang's behaviourGCC 对 std::async(std::launch::async) 的行为与 Clang 的行为
【发布时间】:2012-04-21 00:02:07
【问题描述】:

有人对相当新的std::async 有经验吗?我们目前正在实现一个并行文件解析器,它读取一个文件块并将这个块传递给一个异步函数。

以这种方式使用 Clang (v3.0) 与默认的 std::async 策略(依赖于实现)一起工作非常好。在两核机器上,它可以触发多达 4 个线程,效果非常好。

但是使用 GCC (v4.7),文件读取线程不会产生任何新线程,从而使程序最终完全顺序。

使用std::launch::async,两个版本几乎都在做同样的事情(应该是什么情况)。

有谁知道 GCC 的 c++11 线程能力的当前状态?或者这可能是我们的实现中的一个错误?

短代码:

while (readNewChunk()) {
    Chunk &chunk = fileReader_.getChunk(); //reading the file
    ChunkLoader *chunkLoader = new ChunkLoader();
    auto ftr = std::async(std::launch::async, &ChunkLoader::createDictionaries, chunkLoader);
    dictCreationFutures_.push_back(std::move(ftr));
}

【问题讨论】:

  • 我真的会推荐使用 Boost。对正确的 C++11 支持不会有很大的飞跃。 C++11 中的新线程模型需要与 GCC 或 MSVC 使用的不同的内存布局,而且它们并没有真正实现。

标签: c++ gcc c++11 clang policy


【解决方案1】:

更新的答案:GCC 7.3.0 和 Clang 6.0 都将在默认启动策略的单独线程上执行 std::async() 工作。两者都将创建与 std::async() 调用一样多的线程(经过 100 次调用测试)。

我不知道 GCC 的这种行为何时改变。

【讨论】:

    【解决方案2】:

    所以我知道这是 2 年后的事了,但我不禁觉得有必要回复 @std''OrgnlDave 关于 GCC 与 CLang 的评论,请注意至少目前,2015 年 1 月,两者都是 clang 3.5 版和 GCC 4.9 版具有完全相同的行为。这种行为是,当没有提供启动策略时,默认为不同,并在调用 future::get 时执行,并且只有当显式提供异步启动策略时,编译器才会导致在后台执行函数。

    【讨论】:

      【解决方案3】:

      EDIT2:我再解释一下。

      std::async 承诺一个“未来”;那就是:当你想要它时,它就会出现。现在可以计算,也可以在您要求时计算,我们只是保证会发生。

      就像我下面的海报注释一样,GCC 默认为延迟(这意味着,当它被要求时,它会履行该承诺,并且可能不会事先)。这个默认的原因是因为 GCC 还没有提供适当的 C++11 线程支持。它没有一个好的内部线程调度程序,等等。这有点像黑客。不,更像是一堆黑客。事实上,如果你在 GCC 上用 C++11 编写线程代码,那么当他们实现特性时,它就会正常工作;现在,它大部分工作正常。我的意思是,你最终得到了结果,对吧?

      如果你告诉它启动一个线程,它就会启动一个线程,因为它(目前)太愚蠢了,无法意识到它可以而且应该独立运行(不像 CLang,它目前具有更好的内部线程调度程序)。

      编辑:认真的吗?误导性的下调!

      这是我的参考! http://gcc.gnu.org/projects/cxx0x.html 。请注意,“并发”下的几乎所有内容(包括“内存模型”)都标记为 NO 。 GCC.GNU.org。你知道他们是 GCC 的权威。

      根据我的评论稍作修改:

      我真的会推荐使用 Boost。当 GCC 准备好时,对正确的 C++11 支持不会有很大的飞跃。 C++11 中的新线程模型需要与 GCC 或 MSVC 使用的不同的内存布局,而且它们还没有真正实现。

      【讨论】:

      • C++11 在“内存布局”方面发生了哪些变化?
      • @NicolBolas gcc.gnu.org/projects/cxx0x.html 。注意“并发”下的几乎所有内容,包括“内存模型”,都被标记为 NO
      • 是的,但这并不能解释“内存布局”发生了什么变化。布局是关于事物相对于其他事物的走向。内存模型解释了访问变量何时在其他线程中可见等规则。
      • @NicolBolas 叹息,我们 C++ 人就是这样的书呆子。
      • 我投了赞成票。我认为 GCC 的行为是完全错误的。请参阅我在另一个答案下的评论。
      【解决方案4】:

      行为符合规范,即使它不是您想要的。如果您未指定启动策略,则将其设为async|deferred,这意味着由实现决定哪个。如果可以选择,GCC 碰巧总是选择deferred

      【讨论】:

      • 感谢您解决这个问题。我认为所有当前的实现都有点“更智能”,而不仅仅是做一个普通的 deferred
      • 我不同意。这就是标准所说的(强调我的):“如果此策略与其他策略一起指定,例如当使用 launch::async | launch::deferred 的策略值时,实现应该推迟调用或选择策略 可以有效地利用并发性。”这与延迟启动任何新线程大不相同。
      猜你喜欢
      • 2012-04-01
      • 1970-01-01
      • 2015-08-28
      • 1970-01-01
      • 2012-07-13
      • 1970-01-01
      • 2020-11-19
      • 2019-03-15
      • 1970-01-01
      相关资源
      最近更新 更多