为什么有些线程被推迟了?

时间:2014-12-04 18:49:07

标签: c++ multithreading c++11

在我关注的教程中,作者编写了一个程序,表明std::future的析构函数总是不执行任务。在下面的程序中,使用std::async()创建的10个线程被移动到向量中,然后我们等待它们的析构函数运行。

#include <iostream>
#include <future>
#include <thread>
#include <chrono>

int main()
{
    std::cout << "Main thread id: " << std::this_thread::get_id() << std::endl;

    std::vector<std::future<void>> futures;
    for (int i = 0; i < 10; ++i)
    {
        auto fut = std::async([i]
        {
            std::this_thread::sleep_for(std::chrono::seconds(2));
            std::cout << std::this_thread::get_id() << " ";
        });
        futures.push_back(std::move(fut));
    }
}

结果与机器有关,但我们发现在析构函数运行时只启动了6个线程(在主线程id输出后我们只打印了6个ID)。这意味着其他四个被推迟,延期线程不会在std::future的析构函数中运行。

我的问题是为什么有些线程被迫执行而其他线程被推迟。如果std::future的生命正在结束,那么推迟他们的意义何在?

2 个答案:

答案 0 :(得分:6)

  

作者写了一个程序,表明std :: futures的析构函数并不总是执行任务。

析构函数从不执行任务。如果任务已在另一个线程中执行,则析构函数会等待它完成,但它不会执行它。

  

我们发现在析构函数运行时只启动了6个线程

这是不正确的,线程在析构函数运行时不会启动,它们在您调用std::async时(或之后的某个时间)启动,并且它们在析构函数启动时仍在运行,因此析构函数必须等待对他们来说。

  

如果std :: future的生命结束,那么推迟他们的意义何在?

同样,它们在析构函数运行时不会延迟,它们在调用std::async时会延迟,它们在析构函数运行时仍会延迟,因此它们只是在不运行的情况下被抛弃,并且析构函数不会不得不等待任何事情。

我不知道你是否引用了这个教程,而且这个教程的作者很困惑,或者如果你感到困惑,但你对所发生的事情的描述会产生误导。

每次在没有启动策略参数的情况下调用std::async时,C ++运行时决定是创建新线程还是推迟该函数(因此可以稍后运行)。如果系统繁忙,运行时可能会决定推迟该功能,因为启动另一个线程会使系统更慢。

答案 1 :(得分:2)

您的async()调用使用默认启动策略,launch::async|launch::deferred表示“该功能自动选择策略(在某些时候)。这取决于系统和库实现,这通常会优化系统中当前的并发可用性。“

thread::hardware_concurrency可能会为您提供有关系统上最大硬件并发性的提示。这有助于解释为什么某些线程必须延迟(特别是如果你的循环比硬件并发更大)。但是,请注意其他正在运行的进程也可能使用硬件并发。

请注意,您的异步线程会使用cout,这可能因同步而导致其中一些延迟(更多here