std :: async没有使用std :: launch :: async策略启动新线程

时间:2012-07-14 00:59:41

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

如果我用std :: launch :: async策略启动std :: async,它不应该在新线程中启动每个异步任务吗?目前它看起来新的异步任务转移到刚刚完成它的工作的线程。我正在使用VC11作为我的编译器。正如您从输出中看到的那样,当一个新工作者(例如一个工作者多次获得ID为34500的线程)与std :: async一起启动时,它将在之前完成的线程中启动。我对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.

2 个答案:

答案 0 :(得分:11)

  

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

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

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

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

  

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

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

答案 1 :(得分:6)

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