4

如果我使用 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.
4

2 回答 2

11

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

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

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

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

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

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

于 2012-07-14T01:34:13.060 回答
6

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

于 2012-07-14T17:38:28.800 回答