【问题标题】:Does standard C++11 guarantee that std::async(std::launch::async, func) launches func in separate thread?标准 C++11 是否保证 std::async(std::launch::async, func) 在单独的线程中启动 func ?
【发布时间】:2017-06-19 16:21:21
【问题描述】:

标准 C++11 是否保证 std::async(std::launch::async, func) 在单独的线程中启动函数?

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

1.一方面,C++11-Standard说如果线程不能被创建,那么就会出错。这确保了新线程的创建(在没有错误的情况下)。

§ 30.6.8

6

抛出:system_error if policy == launch::async 和 实现无法启动新线程。

7 错误条件:

(7.1) — resource_unavailable_try_again — 如果 策略 == launch::async 并且系统无法启动新线程

文档说:http://en.cppreference.com/w/cpp/thread/launch

std::launch::async 启动一个新线程来执行任务 异步

2。另一方面,据说可以潜在地创建线程。那些,不必创建线程。

§ 30.6.8

1 函数模板 async 提供了一种机制来启动 函数可能在一个新线程中并提供结果 在与其共享共享状态的未来对象中运行。

而且这里写成好像在一个新线程中,是不是意味着不需要在新的单独线程中?

§ 30.6.8

(3.1)

——如果 policy & launch::async 非零——调用 INVOKE (DECAY_COPY (std::forward(f)), DECAY_COPY (std::forward(args))...) (20.14.2, 30.3.1.2) 好像在一个新线程中 执行 由对 DECAY_COPY () 的调用的线程对象表示 在调用异步的线程中评估。存储任何返回值 作为共享状态的结果。从传播的任何异常 执行 INVOKE (DECAY_COPY (std::forward(f)), DECAY_COPY (std::forward(args))...) 作为异常结果存储在 共享状态。线程对象以共享状态存储,并且 影响任何引用的异步返回对象的行为 那个状态。

当使用 std::async(std::launch::async, func) 时,标准 C++11 是否保证 func() 将在单独的线程中执行,或者它可以在调用 async 的同一线程中执行?

【问题讨论】:

  • 我读到“好像在一个新线程中”的意思是“好像你打电话给std::thread(func)
  • 我认为“好像”是指可观察到的行为就像您在一个新线程中一样。例如,线程局部变量将被初始化和销毁​​。
  • 看起来并不保证会产生一个线程,但它看起来可以保证程序的行为就像你做的那样。它的措辞可能是为了进行一些巧妙的优化。
  • 如果不需要线程怎么办,例如,如果使用 IO 完成端口?在所有语言中,futureasync 功能允许应用程序启动异步操作并在返回时处理其结果。这并不意味着将使用一个线程,或者该线程将是一个新线程。对于真正的异步操作(通常是 IO),您可能根本不需要线程。如果实现使用线程池,您可能会从池中获得一个空闲线程,而不是启动一个新线程。
  • @Panagiotis Kanavos 是的,也许你是对的,如果它使用 IO 完成端口(Proactor 设计模式),它可以使用 OS/C++ 运行时线程池中已经创建的线程。但问题不是“是否会创建一个新线程”,而是“将在另一个线程中执行func() 而不是调用async() 的线程”?那些,这是否保证我可以通过使用std::launch::async 来加速我的程序,在if (std::thread::hardware_concurrency() >= 2) 条件下占用两个可用的CPU 内核?

标签: c++ multithreading c++11 asynchronous c++14


【解决方案1】:

这里的两个关键语句是:

好像在一个由thread 对象表示的新执行线程中

thread 对象存储在共享状态中,并影响任何引用该状态的异步返回对象的行为。

“好像”意味着它的行为必须与为该函数创建std::thread 对象完全相同。这意味着创建std::thread 的所有副作用也必须发生。

话虽如此,如果您将launch::asynclaunch::deferred 结合使用,那么实现将决定是启动一个新线程还是将其推迟到现有线程。所以只有launch::async 需要一个新线程。

【讨论】:

  • 后续问题。如果 std::launch::deferred 决定推迟到现有线程,实现如何处理它?它是否有一些算法来决定何时将它的堆栈帧推入堆栈(它是确定性的)?对不起,如果这个问题没有意义,我是异步的新手。
  • @TylerLewis:标准清楚地表明所有这些都是实现定义的。如果您单独使用deferred,那么它只会在您尝试访问future 时运行。但如果你同时使用asyncdeferred,则实现完全控制函数执行的调度。
猜你喜欢
  • 2012-07-13
  • 2015-08-28
  • 2012-04-01
  • 2019-02-19
  • 1970-01-01
  • 2020-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多