在我关注的教程中,作者编写了一个程序,表明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
的生命正在结束,那么推迟他们的意义何在?
答案 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)