【问题标题】:std::async not starting new threads with std::launch::async policystd::async 未使用 std::launch::async 策略启动新线程
【发布时间】:2012-07-13 20:56:50
【问题描述】:

如果我使用 std::launch::async 策略启动 std::async ,它不应该在新线程中启动每个异步任务吗?目前看起来新的异步任务移动到刚刚完成它的工作的线程。我使用 VC11 作为我的编译器。正如您从输出中看到的那样,当使用 std::async 启动一个新的工作线程(例如,一个工作线程多次获取 ID 为 34500 的线程)时,它从一个先前完成的线程开始。我对 std::async 的理解是错误的,还是有潜在的工作窃取队列或类似的东西?

Worker (ID=24072) starting.
Worker (ID=34500) starting.
Worker (ID=32292) starting.
Worker (ID=31392) starting.
Worker (ID=17976) starting.
Worker (ID=31580) starting.
Worker (ID=33512) starting.
Worker (ID=33804) starting.
Worker 32292 finished.
Worker (ID=32292) starting.
Worker 17976 finished.
Worker (ID=17976) starting.
Worker 31580 finished.
Worker (ID=31580) starting.
Worker 34500 finished.
Worker (ID=34500) starting.
Worker 34500 finished.
Worker (ID=34500) starting.
Worker 32292 finished.
Worker (ID=32292) starting.
Worker 17976 finished.
Worker (ID=17976) starting.
Worker 34500 finished.
Worker 17976 finished. 
Worker 31580 finished.
Worker 32292 finished.
Worker 33804 finished.
Worker 31392 finished.
Worker 33512 finished.
Worker 24072 finished.

【问题讨论】:

  • 认为允许实现将线程池用于新任务,或者至少这是 IIRC 的意图。

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


【解决方案1】:

如果我使用 std::launch::async 策略启动 std::async,它不应该在新线程中启动每个异步任务吗?

规范要求异步操作“就像在新的执行线程中一样”执行(C++11 §30.6.8/11)。这里的重要词是:好像

当且仅当行为与创建新线程相同时,才能重用已经运行的工作线程。这意味着,例如,具有thread_local 存储类的变量必须在单个线程上执行的异步操作之间重置。

没有必要重置线程标识符,因为线程标识符仅在线程运行时唯一标识线程。如果一个线程终止,则可以使用第一个线程的标识符启动另一个线程。

是否有潜在的工作窃取队列或类似的东西?

这是特定于实现的。 C++11 线程支持库的 Visual C++ 2012 实现构建在 Concurrency Runtime (ConcRT) 之上,其中包括一个工作窃取任务调度程序。

【讨论】:

  • 太好了,我不知道 ConcRT。谢谢!
【解决方案2】:

James 是对的,但有一个更正:Microsoft 的 launch::async 实现不正确。 C++ 并发working group in Redmond 对此进行了详细讨论。 Visual C++ 2012 仍处于测试阶段,因此他们可能会将实现更改为符合标准。

【讨论】:

  • 感谢您的博客链接,Bartosz!参加研究组会议会很酷。从您的博客文章中,听起来 VC2012 不符合标准的原因是它不会重置线程本地状态。那是对的吗?我只是想确保我了解不符合项的程度。我最不想做的就是向人们提供不良信息:-)
  • 线程局部变量的破坏是一个问题。主要问题涉及另一个问题:使用有限的固定线程池,您可能会陷入死锁情况。想象一下,所有可用线程都在运行阻塞等待剩余任务向它们发送消息的任务。另一方面,那些剩余的任务正在等待池线程变得可用。如果所有以 launch::async 开始的任务都在不同的线程中同时运行,这种情况就不会发生。
  • 我刚刚使用 Visual C++ 2013 Update 2 用完了 std::async TP 中的线程。达到上限(没有进行精确测量,但在 10 秒内测量),并且池不会超出该限制(即使使用std::launch::async)。切换到std::thread 使限制消失。没想到这种行为......
猜你喜欢
  • 2012-04-01
  • 2020-11-19
  • 1970-01-01
  • 2015-08-28
  • 1970-01-01
  • 1970-01-01
  • 2017-06-19
  • 2020-02-02
  • 2012-04-21
相关资源
最近更新 更多