关于std :: async使用std :: launch :: async参数启动的线程的混淆

kri*_*pet 31 c++ multithreading future c++11 stdthread

我对这个std::async功能有点困惑.

规范说:正在执行的异步操作"好像在新的执行线程中"(C++11§30.6.8/ 11).

现在,这意味着什么?

在我的理解中,代码

std::future<double> fut = std::async(std::launch::async, pow2, num);
Run Code Online (Sandbox Code Playgroud)

应该pow2在新线程上启动函数并将值传递num给线程的值,然后在将来某个时候,当函数完成时,将结果放入fut(只要函数pow2具有类似的签名double pow2(double);).但规范说"似乎",这使得整个事情对我来说有点模糊.

问题是:

在这种情况下是否始终启动新线程?希望如此.我的意思是对我来说,参数std::launch::async是有意义的,我明确说明我确实想要创建一个新线程.

和代码

std::future<double> fut = std::async(std::launch::deferred, pow2, num);
Run Code Online (Sandbox Code Playgroud)

应该通过将函数调用延迟到我写的类似的点来使延迟评估成为可能.在这种情况下,参数,应该意味着我明确说明,我不想要一个新线程,我只是想确保在需要它的返回值时调用该函数.pow2var = fut.get();std::launch::deferred

我的假设是否正确?如果没有,请解释.

另外,我知道默认情况下该函数调用如下:

std::future<double> fut = std::async(std::launch::deferred | std::launch::async, pow2, num);
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我被告知是否将启动新线程取决于实现.那又是什么意思呢?

bku*_*ytt 42

std::async(的部分<future>功能模板头)用于启动(可能)异步任务.它返回一个std::future对象,最终将保存std::async参数函数的返回值.

当需要该值时,我们在std::future实例上调用get(); 这将阻塞线程,直到将来准备就绪,然后返回值.std::launch::async或者std::launch::deferred可以指定为第一个参数,std::async以指定任务的运行方式.

  1. std::launch::async表示函数调用必须在其自己的(新)线程上运行.(将用户@ TC的评论记入帐户).
  2. std::launch::deferred表示函数调用将被推迟到将来调用wait()get()调用.在此之前,未来的所有权可以转移到另一个线程.
  3. std::launch::async | std::launch::deferred表示实施可以选择.这是默认选项(如果您自己未指定).它可以决定同步运行.

在这种情况下是否始终启动新线程?

1开始,我们可以说总是启动一个新线程.

我的假设[在std :: launch :: deferred]是否正确?

2开始,我们可以说你的假设是正确的.

那是什么意思?[关于正在启动或未启动的新线程,取决于实现]

3.,std::launch::async | std::launch::deferred默认选项,它意味着模板函数的实现std::async将决定它是否将创建新线程.这是因为一些实现可能正在检查过度调度.

警告

以下部分与您的问题无关,但我认为重要的是要记住.

C++标准规定,如果a std::future保存对与异步函数调用相对应的共享状态的最后一个引用,则std :: future的析构函数必须阻塞,直到异步运行函数的线程结束.因此std::future返回的实例std::async将在其析构函数中阻塞.

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 ) };
}
Run Code Online (Sandbox Code Playgroud)

这种误导性代码可能会让您认为std::async调用是异步的,它们实际上是同步的.std::future返回的实例std::async是临时的并且将阻塞,因为它们的析构函数在std::async返回时被调用,因为它们未分配给变量.

第一次调用std::async将阻塞2秒,然后再从第二次调用阻止2秒std::async.我们可能认为最后一次调用std::async没有阻塞,因为我们将它返回的std::future实例存储在一个变量中,但由于这是一个在作用域末尾被销毁的局部变量,它实际上会阻塞另外2秒钟.当局部变量f被销毁时,函数范围的结束.

换句话说,调用该operation()函数将阻止它同步调用的任何线程大约6秒.未来版本的C++标准可能不存在此类要求.

我用来编译这些笔记的信息来源:

C++并发行动:实用多线程,Anthony Williams

Scott Meyers的博文:http://scottmeyers.blogspot.ca/2013/03/stdfutures-from-stdasync-arent-special.html

  • 只是为了澄清,如果你在你的例子中将 `std::async` 的普通调用更改为 `auto t1 = std::async(...);`,阻塞时间将只有大约 2 秒,对吗? (2认同)
  • @AdamHunyadi如果你的意思是总阻止时间 - 是的,因为三个不同的线程会同时睡觉. (2认同)
  • 谢谢!我不知道为什么当我强制异步启动时我的调用线程被阻塞。 (2认同)