可以std :: async“重用”线程吗?

时间:2018-01-31 13:34:15

标签: c++ multithreading c++11

如标题中所述,我想知道使用std::async运行的任务是否可以“重用”空闲线程。

例如,让我们采取下一个代码:

auto task = []() { std::this_thread::sleep_for(std::chrono::seconds(20)); };
int tasksCount = 160;
std::vector<std::future<void>> futures;

for (int i = 0; i < tasksCount; ++i)
{
    futures.push_back(std::async(task));
}

所以我们有许多并行运行的任务(160)什么都不做。当此代码在Windows上运行时,它会生成161个等待线程。

无所事事是不是太多线程?为什么等待线程不能“重用”?

3 个答案:

答案 0 :(得分:3)

共享确实发生了,但是在核心级别,而不是线程级别。由于你的线程几乎没有计算,所以160个线程可能共享一个CPU核心。

从根本上说,一个线程拥有一个调用堆栈,其中包含每个函数调用的局部变量。这个堆栈实际上无法共享 - 调用堆栈的基本属性是top函数是主动执行的函数。在您的示例中,您在160个堆栈之上有160 sleep_for

答案 1 :(得分:2)

粗略地说,一个线程是堆栈的CPU状态和保留存储空间,以及OS调度程序中的一个条目。 C ++语言还包含有关每线程状态(thread_local)的信息,而辅助库也可能具有某些状态。

这些价​​格相当昂贵。这些信息不能在线程之间共享;每个线程实际上有一个不同的堆栈,一组不同的thread_local状态,不同的寄存器值等等。

现在,当一个线程没有执行时,它只是一个表中的一个条目。没有CPU资源(除了由较大的表引起的那些)在线程上花费。所以你有大量的设置成本,一堆线程启动,然后他们去睡觉。调度程序在他们要求睡眠的时间到来之前不会返回这些线程。

因此,在硬件层面,他们正在共享CPU。但是在软件级别,它们的状态不是共享的,而这正是您在调试器中看到的。

答案 2 :(得分:1)

重要的问题是:它会对您的计划产生什么样的可观察差异?该标准不会谈论在低系统级别发生的事情。它只会谈论可观察的行为。那里没有任何收获,唯一可观察到的差异可能是意外的线程局部存储变量混淆。

考虑复杂性:

  • 睡眠线程不会给系统带来太多损失。拥有更多空闲线程不会伤害太多
  • 繁忙的线程无法重复使用。好吧,不是没有成本。
  • 如果你想重用空闲线程,你怎么知道重用后的线程在睡觉后不会变忙。

因此,简而言之,它不会提供任何明显的好处,可能会破坏线程本地存储,具体取决于规范中的说明方式,并且将是一个很大的难点。只是为了减少较低级别的线程数。