2012-02-20 46 views
12

我一直在考虑std::async以及如何在未来的编译器实现中使用它。但是,现在我有点卡住了感觉像设计缺陷的东西。std :: async - 与实现相关的用法?

std::async几乎与实现有关,可能有两个变种launch::async,一个将任务启动到新线程中,另一个使用线程池/任务调度程序。

但是,根据用于实施std::async的这些变体中的哪一个,使用情况会有很大差异。

对于基于“线程池”的变体,您将能够启动大量小型任务,而不用担心很多开销,但是,如果其中一个任务在某个时间点阻塞了,该怎么办?

另一方面,“启动新线程”变体不会遇到阻塞任务的问题,另一方面,启动和执行任务的开销将非常高。

线程池: +低开销,-never曾经阻止

推出新的线程: +罚款块,志高开销

所以基本上取决于实施,我们使用std::async的方式会非常谨慎。如果我们有一个与一个编译器兼容的程序,它可能会在另一个编译器上运行。

这是设计吗?或者我错过了什么?你会认为这个和我一样是个大问题吗?

在当前的规范中,我缺少类似std::oversubscribe(bool)的内容,以便实现依赖于std::async的使用。

编辑:据我已阅读,C++ 11标准文档不会给任何提示关于发送到std::async的任务是否可能会阻塞。

+0

就像一个加法:http://en.cppreference.com/w/cpp/thread/async提供了一个非常简单而实际的阻止'std :: async'调用的例子。 – KillianDS 2012-02-20 15:50:29

+0

您似乎认为线程池具有固定的大小。实际上,很多都是动态调整大小的,所以阻塞不是问题。 – 2014-01-22 23:24:13

+0

@MooingDuck:TBB和Concrt都没有“动态”大小的线程池。你知道哪些线程池是动态调整大小的?即使你有一个动态调整大小的线程池,你反而会遇到超额订阅的问题,并且需要任何启发式的开销来跟踪何时添加新线程和删除旧线程。 – ronag 2014-01-22 23:31:42

回答

11

std::async任务,std::launch::async运行的政策推出“仿佛在一个新的线程”,所以线程池是不是真的支持---运行时将不得不推倒并重建中的每个之间的所有线程局部变量任务执行,这并不简单。

这也意味着您可以期望以std::launch::async策略开始的任务可以同时运行。可能会有一个启动延迟,如果你有更多的运行线程比处理器有更多的运行线程,那么会有任务切换,但是它们应该是运行的,而不是因为发生了等待另一个而发生死锁。

实现可能会选择提供扩展,它允许您的任务在线程池中运行,在这种情况下,需要由该实现来记录语义。

+1

+1,用于“好像在新线程中”和线程局部变量。 – ronag 2012-02-20 15:46:07

+0

MSVC的异步使用线程池。我想象一下,当一个线程完成一个“任务”时,它会报告完成情况,然后重置它的线程本地,然后等待一个新的任务。这意味着用户代码永远不必等待线程本地重置。 – 2014-01-22 23:26:36

+0

我不知道MSVC实现的细节,但是该标准要求'thread_local'变量在'future'准备好之前销毁。 – 2014-01-23 16:57:26

1

我期望实现启动新线程,并将线程池留给未来版本的C++来标准化它。有没有使用线程池的实现?


MSVC根据其并发运行时初始使用线程池。根据STL Fixes In VS 2015, Part 2这已被删除。 C++规范给实施者留下了一些空间让聪明的人做事,但我认为这不足以为这个线程池实施留下足够的空间。特别是我认为该规范仍然要求thread_local对象将被销毁和重建,但与ConcRT的线程池将不会支持。

+1

如果我没有记错,微软在Going Native 2012会议期间宣布'std :: async'会使用Concrt。我不知道gcc和clang有什么计划。 – ronag 2012-02-20 15:43:01

+0

MSVC确实在此时使用了一个线程池,最后我检查了libC++和libstdC++都没有使用池。 – 2014-01-22 23:28:28

相关问题