使用std :: launch :: async参数对由std :: async启动的线程感到困惑
我对std::async
函数有点困惑。
规范说:正在执行的异步操作“就像在一个新的执行线程中一样”(C ++ 11§30.6.8/ 11)。
现在,这是什么意思?
在我的理解中,代码
std::future<double> fut = std::async(std::launch::async, pow2, num);
应该在一个新的线程上启动函数pow2
,并通过值将该变量num
传递给线程,然后在将来某个时候,当函数完成时,将结果放在fut
(只要函数pow2
具有像double pow2(double);
这样的签名double pow2(double);
)。 但规格说明“仿佛”,这使整个事情有点雾对我来说。
问题是:
在这种情况下总是启动一个新线程? 但愿如此。 我的意思是对于我来说,参数std::launch::async
是有道理的,我明确指出我确实想要创建一个新线程。
和代码
std::future<double> fut = std::async(std::launch::deferred, pow2, num);
应该通过延迟pow2
函数调用到我写类似var = fut.get();
地方来进行懒惰评估 var = fut.get();
。 在这种情况下, std::launch::deferred
参数应该表示我明确指出,我不想要一个新线程,我只是想确保函数在需要返回值时被调用。
我的假设是否正确? 如果没有,请解释。
另外,我知道默认情况下,函数调用如下:
std::future<double> fut = std::async(std::launch::deferred | std::launch::async, pow2, num);
在这种情况下,我被告知是否会启动一个新线程取决于实现。 再次, 这是什么意思?
std::async
( <future>
标头的一部分)函数模板用于启动(可能)异步任务。 它返回一个std::future
对象,它将最终保存std::async
的参数函数的返回值。
当需要该值时,我们在std::future
实例上调用get(); 这会阻塞线程,直到未来准备就绪,然后返回值。 std::launch::async
或std::launch::deferred
指定为std::async
的第一个参数,以便指定任务的运行方式。
std::launch::async
指示函数调用必须在其自己的(新)线程上运行。 (考虑到用户@TC的评论)。 std::launch::deferred
表示函数调用将被延迟,直到将来调用wait()
或get()
。 在这种情况发生之前,未来的所有权可以转移到另一个线程。 std::launch::async | std::launch::deferred
std::launch::async | std::launch::deferred
表示实现可以选择。 这是默认选项(如果您自己没有指定)。 它可以决定同步运行。 在这种情况下总是启动一个新线程?
从1开始 ,我们可以说总是启动一个新线程。
我的假设[在std :: launch :: deferred]是否正确?
从2开始 ,我们可以说你的假设是正确的。
这是什么意思? [关于正在启动或未启动的新线程)
从3. ,作为std::launch::async | std::launch::deferred
std::launch::async | std::launch::deferred
是默认选项,这意味着模板函数std::async
将决定它是否会创建一个新线程。 这是因为有些实现可能正在检查过度调度。
警告
以下部分与您的问题无关,但我认为务必牢记。
C ++标准说,如果一个std::future
对调用异步函数的共享状态的最后一个引用,std :: future的析构函数必须阻塞,直到异步运行函数的线程完成。 因此std::async
返回的std::future
实例会在其析构函数中被阻塞。
void operation()
{
auto func = [] { std::this_thread::sleep_for( std::chrono::seconds( 2 ) ); };
std::async( std::launch::async, func );
std::async( std::launch::async, func );
std::future<void> f{ std::async( std::launch::async, func ) };
}
这个误导性的代码可以让你认为std::async
调用是异步的,它们实际上是同步的。 std::async
返回的std::future
实例是临时的,并且会被阻塞,因为它们的析构函数在std::async
返回时被调用,因为它们没有被分配给变量。
第一次调用std::async
将会阻塞2秒,然后再从第二次调用阻塞到std::async
。 我们可能认为最后一次调用std::async
不会阻塞,因为我们将返回的std::future
实例存储在一个变量中,但是由于这是一个本地变量,它在范围末尾被销毁,它实际上会在局部变量f被破坏时,在函数范围的末尾再封锁2秒。
换句话说,调用operation()
函数将阻止它同步调用的任何线程大约6秒钟。 未来版本的C ++标准中可能不存在这样的要求。
我用来编制这些注释的信息来源:
C ++ Concurrency in Action:实用多线程,Anthony Williams
Scott Meyers的博客文章:http://scottmeyers.blogspot.ca/2013/03/stdfutures-from-stdasync-arent-special.html
我也对此感到困惑,并在Windows上进行了一次快速测试,结果表明异步未来将在OS线程池线程上运行。 一个简单的应用程序可以证明这一点,在Visual Studio中展开也会显示名为“TppWorkerThread”的执行线程。
#include <future>
#include <thread>
#include <iostream>
using namespace std;
int main()
{
cout << "main thread id " << this_thread::get_id() << endl;
future<int> f1 = async(launch::async, [](){
cout << "future run on thread " << this_thread::get_id() << endl;
return 1;
});
f1.get();
future<int> f2 = async(launch::async, [](){
cout << "future run on thread " << this_thread::get_id() << endl;
return 1;
});
f2.get();
future<int> f3 = async(launch::async, [](){
cout << "future run on thread " << this_thread::get_id() << endl;
return 1;
});
f3.get();
cin.ignore();
return 0;
}
将导致类似于以下的输出:
main thread id 4164
future run on thread 4188
future run on thread 4188
future run on thread 4188
事实并非如此。 添加thread_local
存储值,你会看到,实际上std::async run f1 f2 f3
在不同线程中std::async run f1 f2 f3
任务,但是使用相同的std::thread::id
上一篇: Confusion about threads launched by std::async with std::launch::async parameter
下一篇: Can I use std::async without waiting for the future limitation?