Mar*_*ayr 19 c++ future c++11 c++14
在代码审查期间,我遇到了一段代码,基本上归结为:
#include <iostream>
#include <future>
#include <thread>
int main( int, char ** )
{
std::atomic<int> x( 0 );
std::future<void> task;
for( std::size_t i = 0u; i < 5u; ++i )
{
task = std::async( std::launch::async, [&x, i](){
std::this_thread::sleep_for( std::chrono::seconds( 2u * ( 5u - i ) ) );
++x;
} );
}
task.get();
std::cout << x << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我不确定是否
我无法通过阅读互联网上的文档来回答这个问题,所以我想我会编写上面的代码段来找出我们的编译器实际上做了什么.
现在,我发现gcc-5所做的答案是优柔寡断的,这让我更加好奇:人们会认为这个任务要么是阻止的,要么是非阻塞的.
如果它是阻塞的,程序所花费的时间基本上应该是各个任务执行所花费的时间的总和.第一个需要10秒,第二个8秒,第三个6秒,第四个4秒和最后2秒.所以总共需要10 + 8 + 6 + 4 + 2 = 30秒.
如果它是非阻塞的,则应该与上一个任务一样长,即2秒.
这是发生的事情:它需要18秒(使用时间./a.out或一个好的旧时钟测量).通过使用代码进行一些操作,我发现代码的行为就像赋值将交替阻塞和非阻塞一样.
但这不可能是真的,对吧?std::async可能会回到std::deferred一半的时间?我的调试器说它产生两个线程,阻塞直到两个线程都退出,然后产生另外两个线程,依此类推.
标准说什么?应该怎么办?gcc-5里面发生了什么?
Hol*_*olt 12
在一般情况下,的分配task通过operator=(&&)不必是阻塞(见下文),但因为你创建的std::future使用std::async,这些任务变得阻塞(感谢@TC):
如果实现选择launch :: async策略,
[...]
关联的线程完成与([intro.multithread])同步,从第一个函数返回,该函数成功检测到共享状态的就绪状态,或者从释放共享状态的最后一个函数返回,以先发生者为准.
在你的情况下发生的是在分配之前std::async启动lambda的"线程" - 有关如何获得18秒的执行时间的详细说明,请参见下文.
这是(可能)在您的代码(e代表epsilon)中发生的事情:
t = 0,先std::async打电话i = 0,开始一个新线程;t = 0 + e,第二次std::async调用i = 1启动一个新线程,然后移动.此举将释放当前共享状态的task,阻断约10秒(但是第二std::async与i = 1已经执行);t = 10,第三次std::async调用i = 2启动一个新线程,然后移动.当前的共享状态的task是与呼叫i = 1这是早就准备好了所以没有什么块;t = 10 + e,第四次std::async调用i = 3启动一个新线程,然后移动.此举是阻止因为以前std::async有i = 2没有准备好,但线程i = 3为已经启动;t = 16,第五次std::async调用i = 4启动一个新线程,然后移动.当前共享状态的task(i = 3)是已经准备好了,所以无阻塞;t = 16 + e,在循环之外,调用.get()等待*共享状态`准备就绪;t = 18,共享状态变得准备好所以整个事情结束.std::future::operator=:以下是operator=on 的标准报价std::future:
Run Code Online (Sandbox Code Playgroud)future& operator=(future&& rhs) noexcept;功效:
- (10.1) - 释放任何共享状态(30.6.4).
- ...
以下是"释放任何共享状态"的意思(重点是我的):
当异步返回对象或异步提供程序被称为释放其共享状态时,它意味着:
(5.1) - [...]
(5.2) - [...]
(5.3) - 这些操作不会阻止共享状态准备就绪,除非它可能阻塞以下所有条件都是真的:共享状态是通过调用std :: async创建的,共享状态还没有准备好了,这是共享状态的最后一个引用.
你的情况属于我所强调的(我认为).你创建了共享状态std::async,它正在休眠(所以没有准备好),你只有一个引用,所以这可能是阻塞.
| 归档时间: |
|
| 查看次数: |
909 次 |
| 最近记录: |