std::async 的工作原理:为什么它会多次调用 copy/move?
How std::async works: why it invokes copy/move so many times?
基本上是标题
#include <iostream>
#include <future>
class A
{
public:
A () {};
A (const A& a) {std::cout<<"A copy\n";};
A (A&& a) noexcept {std::cout<<"A move\n";};
~A () {std::cout<<"A dest\n";};
void fun () { std::cout<<"fun\n";}
};
int main()
{
A a;
std::future<void> f = std::async([](A a) { a.fun(); }, std::move(a));
f.wait();
return 0;
}
结果是
A move
A move
A dest
A move
fun
A dest
A dest
A dest
一步是把一个object传递给一个async,一个是传递给async里面的函数,但是还有一步是做什么的?
首先,不需要移动将值传递给async()
,转发引用只是绑定到原始值。
然后,与其猜测,不如问问程序本身为什么要生成 copies/moves。
$ g++ --version; g++ -g ./a.cpp -pthread
g++ (Debian 8.3.0-6) 8.3.0
$ gdb ./a.out
GNU gdb (Debian 8.2.1-2+b3) 8.2.1
Reading symbols from ./a.out...done.
(gdb) b 9
Breakpoint 1 at 0x5b78: file ./a.cpp, line 9.
(gdb) r
Starting program: ./a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, A::A (this=0x7ffffffedbdf, a=...) at ./a.cpp:9
9 A (A&& a) noexcept {std::cout<<"A move\n";};
(gdb) bt
#0 A::A (this=0x7ffffffedbdf, a=...) at ./a.cpp:9
#1 0x00000000080070ba in std::_Head_base<1ul, A, true>::_Head_base<A> (this=0x7ffffffedbdf, __h=...) at /usr/include/c++/8/tuple:87
#2 0x0000000008007088 in std::_Tuple_impl<1ul, A>::_Tuple_impl<A> (this=0x7ffffffedbdf, __head=...) at /usr/include/c++/8/tuple:366
#3 0x000000000800286c in std::_Tuple_impl<0, main()::<lambda(A)>, A>::_Tuple_impl<main()::<lambda(A)>, A>(<lambda(A)> &&, A &&) (this=0x7ffffffedbdf, __head=...)
at /usr/include/c++/8/tuple:218
#4 0x0000000008002831 in std::tuple<main()::<lambda(A)>, A>::tuple<main()::<lambda(A)>, A>(<lambda(A)> &&, A &&) (this=0x7ffffffedbdf, __a1=..., __a2=...)
at /usr/include/c++/8/tuple:972
#5 0x00000000080028d1 in std::thread::__make_invoker<main()::<lambda(A)>, A>(<lambda(A)> &&, A &&) (__callable=..., __args#0=...) at /usr/include/c++/8/thread:268
#6 0x0000000008002600 in std::async<main()::<lambda(A)>, A>(std::launch, <lambda(A)> &&, A &&) (__policy=(std::launch::async | std::launch::deferred), __fn=..., __args#0=...)
at /usr/include/c++/8/future:1719
#7 0x00000000080024d3 in std::async<main()::<lambda(A)>, A>(<lambda(A)> &&, A &&) (__fn=..., __args#0=...) at /usr/include/c++/8/future:1749
#8 0x000000000800241c in main () at ./a.cpp:17
(gdb) c
Continuing.
A move
Breakpoint 1, A::A (this=0x8022ec8, a=...) at ./a.cpp:9
9 A (A&& a) noexcept {std::cout<<"A move\n";};
(gdb) bt
#0 A::A (this=0x8022ec8, a=...) at ./a.cpp:9
#1 0x00000000080070ba in std::_Head_base<1ul, A, true>::_Head_base<A> (this=0x8022ec8, __h=...) at /usr/include/c++/8/tuple:87
#2 0x0000000008007056 in std::_Tuple_impl<1ul, A>::_Tuple_impl (this=0x8022ec8, __in=...) at /usr/include/c++/8/tuple:373
#3 0x0000000008002ab0 in std::_Tuple_impl<0, main()::<lambda(A)>, A>::_Tuple_impl(std::_Tuple_impl<0, main()::<lambda(A)>, A> &&) (this=0x8022ec8, __in=...)
at /usr/include/c++/8/tuple:227
#4 0x00000000080027e9 in std::tuple<main()::<lambda(A)>, A>::tuple(std::tuple<main()::<lambda(A)>, A> &&) (this=0x8022ec8) at /usr/include/c++/8/tuple:987
#5 0x0000000008003be3 in std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >::_Invoker(std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > &&) (this=0x8022ec8)
at /usr/include/c++/8/thread:231
#6 0x0000000008003da5 in std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>::_Async_state_impl(std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > &&) (this=0x8022e90, __fn=...) at /usr/include/c++/8/future:1662
#7 0x0000000008003a61 in __gnu_cxx::new_allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> >::construct<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > >(std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> *, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > &&) (this=0x7ffffffeda2f,
__p=0x8022e90, __args#0=...) at /usr/include/c++/8/ext/new_allocator.h:136
#8 0x0000000008003816 in std::allocator_traits<std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> > >::construct<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > >(std::allocator_traits<std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> > >::allocator_type &, std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> *, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > &&) (__a=..., __p=0x8022e90,
__args#0=...) at /usr/include/c++/8/bits/alloc_traits.h:475
#9 0x000000000800344f in std::_Sp_counted_ptr_inplace<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>, std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> >, (__gnu_cxx::_Lock_policy)2>::_Sp_counted_ptr_inplace<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > >(std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> >, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > &&) (this=0x8022e80, __a=...) at /usr/include/c++/8/bits/shared_ptr_base.h:545
#10 0x000000000800306f in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>, std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> >, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > >(std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> *&, std::_Sp_alloc_shared_tag<std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> > >, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > &&) (
this=0x7ffffffedb78, __p=@0x7ffffffedb70: 0x0, __a=...) at /usr/include/c++/8/bits/shared_ptr_base.h:677
#11 0x0000000008002f4c in std::__shared_ptr<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>, (__gnu_cxx::_Lock_policy)2>::__shared_ptr<std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> >, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > >(std::_Sp_alloc_shared_tag<std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> > >, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > &&) (this=0x7ffffffedb70, __tag=...) at /usr/include/c++/8/bits/shared_ptr_base.h:1342
#12 0x0000000008002ea1 in std::shared_ptr<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> >::shared_ptr<std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> >, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > >(std::_Sp_alloc_shared_tag<std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> > >, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > &&) (this=0x7ffffffedb70, __tag=...) at /usr/include/c++/8/bits/shared_ptr.h:359
#13 0x0000000008002cfd in std::allocate_shared<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>, std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> >, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > >(const std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> > &, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > &&) (__a=...,
__args#0=...) at /usr/include/c++/8/bits/shared_ptr.h:706
#14 0x0000000008002b49 in std::make_shared<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > >(std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > &&) (__args#0=...) at /usr/include/c++/8/bits/shared_ptr.h:722
#15 0x00000000080029c4 in std::__future_base::_S_make_async_state<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > >(std::thread::_Invoker<std::tuple<main()::<lambda(A)>,--Type <RET> for more, q to quit, c to continue without paging--c
A> > &&) (__fn=...) at /usr/include/c++/8/future:1705
#16 0x0000000008002613 in std::async<main()::<lambda(A)>, A>(std::launch, <lambda(A)> &&, A &&) (__policy=(std::launch::async | std::launch::deferred), __fn=..., __args#0=...) at /usr/include/c++/8/future:1719
#17 0x00000000080024d3 in std::async<main()::<lambda(A)>, A>(<lambda(A)> &&, A &&) (__fn=..., __args#0=...) at /usr/include/c++/8/future:1749
#18 0x000000000800241c in main () at ./a.cpp:17
(gdb) c
Continuing.
A move
[New Thread 0x7fffff250700 (LWP 141)]
A dest
[Switching to Thread 0x7fffff250700 (LWP 141)]
Thread 2 "a.out" hit Breakpoint 1, A::A (this=0x7fffff24f98f, a=...) at ./a.cpp:9
9 A (A&& a) noexcept {std::cout<<"A move\n";};
(gdb) bt
#0 A::A (this=0x7fffff24f98f, a=...) at ./a.cpp:9
#1 0x000000000800291c in std::__invoke_impl<void, main()::<lambda(A)>, A>(std::__invoke_other, <lambda(A)> &&, A &&) (__f=..., __args#0=...)
at /usr/include/c++/8/bits/invoke.h:60
#2 0x0000000008002525 in std::__invoke<main()::<lambda(A)>, A>(<lambda(A)> &&, A &&) (__fn=..., __args#0=...) at /usr/include/c++/8/bits/invoke.h:95
#3 0x00000000080046bb in std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >::_M_invoke<0, 1>(std::_Index_tuple<0, 1>) (this=0x8022ec8) at /usr/include/c++/8/thread:244
#4 0x0000000008004642 in std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >::operator()(void) (this=0x8022ec8) at /usr/include/c++/8/thread:253
#5 0x0000000008004413 in std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>::operator()(void) const (this=0x7fffff24fdd0) at /usr/include/c++/8/future:1362
#6 0x000000000800413d in std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>(), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> >::_M_invoke(const std::_Any_data &) (__functor=...) at /usr/include/c++/8/bits/std_function.h:283
#7 0x0000000008006067 in std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const (this=0x7fffff24fdd0)
at /usr/include/c++/8/bits/std_function.h:687
#8 0x000000000800599b in std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) (this=0x8022e90, __f=0x7fffff24fdd0, __did_set=0x7fffff24fd47) at /usr/include/c++/8/future:561
#9 0x0000000008006db3 in std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) (__f=
@0x7fffff24fd60: (void (std::__future_base::_State_baseV2::*)(std::__future_base::_State_baseV2 * const, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()> *, bool *)) 0x8005974 <std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*)>, __t=@0x7fffff24fd58: 0x8022e90, __args#0=@0x7fffff24fd50: 0x7fffff24fdd0, __args#1=@0x7fffff24fd48: 0x7fffff24fd47)
at /usr/include/c++/8/bits/invoke.h:73
#10 0x0000000008006633 in std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) (__fn=
@0x7fffff24fd60: (void (std::__future_base::_State_baseV2::*)(std::__future_base::_State_baseV2 * const, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()> *, bool *)) 0x8005974 <std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*)>, __args#0=@0x7fffff24fd58: 0x8022e90, __args#1=@0x7fffff24fd50: 0x7fffff24fdd0, __args#2=@0x7fffff24fd48: 0x7fffff24fd47)
at /usr/include/c++/8/bits/invoke.h:95
#11 0x0000000008005e30 in std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const (this=0x7fffff24fce0) at /usr/include/c++/8/mutex:672
#12 0x0000000008005e5b in std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::operator()() const (this=0x0) at /usr/include/c++/8/mutex:677
#13 0x0000000008005e6c in std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_bas--Type <RET> for more, q to quit, c to continue without paging--c
e::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::_FUN() () at /usr/include/c++/8/mutex:677
#14 0x00007fffff45e997 in __pthread_once_slow (once_control=0x8022ea8, init_routine=0x7fffff6dae20 <__once_proxy>) at pthread_once.c:116
#15 0x00000000080023bd in __gthread_once (__once=0x8022ea8, __func=0x7fffff6dae20 <__once_proxy>) at /usr/include/x86_64-linux-gnu/c++/8/bits/gthr-default.h:699
#16 0x0000000008005f05 in std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) (__once=..., __f=@0x7fffff24fd60: (void (std::__future_base::_State_baseV2::*)(std::__future_base::_State_baseV2 * const, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()> *, bool *)) 0x8005974 <std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*)>, __args#0=@0x7fffff24fd58: 0x8022e90, __args#1=@0x7fffff24fd50: 0x7fffff24fdd0, __args#2=@0x7fffff24fd48: 0x7fffff24fd47) at /usr/include/c++/8/mutex:684
#17 0x000000000800577c in std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>, bool) (this=0x8022e90, __res=..., __ignore_failure=false) at /usr/include/c++/8/future:401
#18 0x0000000008003c49 in std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>::<lambda()>::operator()(void) const (this=0x8022e90) at /usr/include/c++/8/future:1667
#19 0x000000000800431d in std::__invoke_impl<void, std::__future_base::_Async_state_impl<_BoundFn, _Res>::_Async_state_impl(_BoundFn&&) [with _BoundFn = std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >; _Res = void]::<lambda()> >(std::__invoke_other, std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>::<lambda()> &&) (__f=...) at /usr/include/c++/8/bits/invoke.h:60
#20 0x000000000800401e in std::__invoke<std::__future_base::_Async_state_impl<_BoundFn, _Res>::_Async_state_impl(_BoundFn&&) [with _BoundFn = std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >; _Res = void]::<lambda()> >(std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>::<lambda()> &&) (__fn=...) at /usr/include/c++/8/bits/invoke.h:95
#21 0x0000000008004d80 in std::thread::_Invoker<std::tuple<std::__future_base::_Async_state_impl<_BoundFn, _Res>::_Async_state_impl(_BoundFn&&) [with _BoundFn = std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >; _Res = void]::<lambda()> > >::_M_invoke<0>(std::_Index_tuple<0>) (this=0x8022f08) at /usr/include/c++/8/thread:244
#22 0x0000000008004cd6 in std::thread::_Invoker<std::tuple<std::__future_base::_Async_state_impl<_BoundFn, _Res>::_Async_state_impl(_BoundFn&&) [with _BoundFn = std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >; _Res = void]::<lambda()> > >::operator()(void) (this=0x8022f08) at /usr/include/c++/8/thread:253
#23 0x00000000080048b0 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<std::__future_base::_Async_state_impl<_BoundFn, _Res>::_Async_state_impl(_BoundFn&&) [with _BoundFn = std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >; _Res = void]::<lambda()> > > >::_M_run(void) (this=0x8022f00) at /usr/include/c++/8/thread:196
#24 0x00007fffff6dbb2f in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#25 0x00007fffff456fa3 in start_thread (arg=<optimized out>) at pthread_create.c:486
#26 0x00007fffff3794cf in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
(gdb) c
Continuing.
A move
fun
A dest
A dest
[Thread 0x7fffff250700 (LWP 141) exited]
A dest
[Inferior 1 (process 137) exited normally]
(gdb)
如我们所见:
第一步是创建调用程序 (std::thread::__make_invoker()
)。调用程序是一种打包任务,以后可以作为一个单元执行。
第二步发生在将调用程序打包到 async_state
对象并将其存储在 future
(__future_base::_S_make_async_state()
)
第三步发生在调用lambda时(_State::_M_run()
)
所有这些都是实现细节,可能会在标准库的版本之间发生变化。
基本上是标题
#include <iostream>
#include <future>
class A
{
public:
A () {};
A (const A& a) {std::cout<<"A copy\n";};
A (A&& a) noexcept {std::cout<<"A move\n";};
~A () {std::cout<<"A dest\n";};
void fun () { std::cout<<"fun\n";}
};
int main()
{
A a;
std::future<void> f = std::async([](A a) { a.fun(); }, std::move(a));
f.wait();
return 0;
}
结果是
A move
A move
A dest
A move
fun
A dest
A dest
A dest
一步是把一个object传递给一个async,一个是传递给async里面的函数,但是还有一步是做什么的?
首先,不需要移动将值传递给async()
,转发引用只是绑定到原始值。
然后,与其猜测,不如问问程序本身为什么要生成 copies/moves。
$ g++ --version; g++ -g ./a.cpp -pthread
g++ (Debian 8.3.0-6) 8.3.0
$ gdb ./a.out
GNU gdb (Debian 8.2.1-2+b3) 8.2.1
Reading symbols from ./a.out...done.
(gdb) b 9
Breakpoint 1 at 0x5b78: file ./a.cpp, line 9.
(gdb) r
Starting program: ./a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, A::A (this=0x7ffffffedbdf, a=...) at ./a.cpp:9
9 A (A&& a) noexcept {std::cout<<"A move\n";};
(gdb) bt
#0 A::A (this=0x7ffffffedbdf, a=...) at ./a.cpp:9
#1 0x00000000080070ba in std::_Head_base<1ul, A, true>::_Head_base<A> (this=0x7ffffffedbdf, __h=...) at /usr/include/c++/8/tuple:87
#2 0x0000000008007088 in std::_Tuple_impl<1ul, A>::_Tuple_impl<A> (this=0x7ffffffedbdf, __head=...) at /usr/include/c++/8/tuple:366
#3 0x000000000800286c in std::_Tuple_impl<0, main()::<lambda(A)>, A>::_Tuple_impl<main()::<lambda(A)>, A>(<lambda(A)> &&, A &&) (this=0x7ffffffedbdf, __head=...)
at /usr/include/c++/8/tuple:218
#4 0x0000000008002831 in std::tuple<main()::<lambda(A)>, A>::tuple<main()::<lambda(A)>, A>(<lambda(A)> &&, A &&) (this=0x7ffffffedbdf, __a1=..., __a2=...)
at /usr/include/c++/8/tuple:972
#5 0x00000000080028d1 in std::thread::__make_invoker<main()::<lambda(A)>, A>(<lambda(A)> &&, A &&) (__callable=..., __args#0=...) at /usr/include/c++/8/thread:268
#6 0x0000000008002600 in std::async<main()::<lambda(A)>, A>(std::launch, <lambda(A)> &&, A &&) (__policy=(std::launch::async | std::launch::deferred), __fn=..., __args#0=...)
at /usr/include/c++/8/future:1719
#7 0x00000000080024d3 in std::async<main()::<lambda(A)>, A>(<lambda(A)> &&, A &&) (__fn=..., __args#0=...) at /usr/include/c++/8/future:1749
#8 0x000000000800241c in main () at ./a.cpp:17
(gdb) c
Continuing.
A move
Breakpoint 1, A::A (this=0x8022ec8, a=...) at ./a.cpp:9
9 A (A&& a) noexcept {std::cout<<"A move\n";};
(gdb) bt
#0 A::A (this=0x8022ec8, a=...) at ./a.cpp:9
#1 0x00000000080070ba in std::_Head_base<1ul, A, true>::_Head_base<A> (this=0x8022ec8, __h=...) at /usr/include/c++/8/tuple:87
#2 0x0000000008007056 in std::_Tuple_impl<1ul, A>::_Tuple_impl (this=0x8022ec8, __in=...) at /usr/include/c++/8/tuple:373
#3 0x0000000008002ab0 in std::_Tuple_impl<0, main()::<lambda(A)>, A>::_Tuple_impl(std::_Tuple_impl<0, main()::<lambda(A)>, A> &&) (this=0x8022ec8, __in=...)
at /usr/include/c++/8/tuple:227
#4 0x00000000080027e9 in std::tuple<main()::<lambda(A)>, A>::tuple(std::tuple<main()::<lambda(A)>, A> &&) (this=0x8022ec8) at /usr/include/c++/8/tuple:987
#5 0x0000000008003be3 in std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >::_Invoker(std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > &&) (this=0x8022ec8)
at /usr/include/c++/8/thread:231
#6 0x0000000008003da5 in std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>::_Async_state_impl(std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > &&) (this=0x8022e90, __fn=...) at /usr/include/c++/8/future:1662
#7 0x0000000008003a61 in __gnu_cxx::new_allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> >::construct<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > >(std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> *, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > &&) (this=0x7ffffffeda2f,
__p=0x8022e90, __args#0=...) at /usr/include/c++/8/ext/new_allocator.h:136
#8 0x0000000008003816 in std::allocator_traits<std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> > >::construct<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > >(std::allocator_traits<std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> > >::allocator_type &, std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> *, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > &&) (__a=..., __p=0x8022e90,
__args#0=...) at /usr/include/c++/8/bits/alloc_traits.h:475
#9 0x000000000800344f in std::_Sp_counted_ptr_inplace<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>, std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> >, (__gnu_cxx::_Lock_policy)2>::_Sp_counted_ptr_inplace<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > >(std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> >, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > &&) (this=0x8022e80, __a=...) at /usr/include/c++/8/bits/shared_ptr_base.h:545
#10 0x000000000800306f in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>, std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> >, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > >(std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> *&, std::_Sp_alloc_shared_tag<std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> > >, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > &&) (
this=0x7ffffffedb78, __p=@0x7ffffffedb70: 0x0, __a=...) at /usr/include/c++/8/bits/shared_ptr_base.h:677
#11 0x0000000008002f4c in std::__shared_ptr<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>, (__gnu_cxx::_Lock_policy)2>::__shared_ptr<std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> >, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > >(std::_Sp_alloc_shared_tag<std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> > >, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > &&) (this=0x7ffffffedb70, __tag=...) at /usr/include/c++/8/bits/shared_ptr_base.h:1342
#12 0x0000000008002ea1 in std::shared_ptr<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> >::shared_ptr<std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> >, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > >(std::_Sp_alloc_shared_tag<std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> > >, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > &&) (this=0x7ffffffedb70, __tag=...) at /usr/include/c++/8/bits/shared_ptr.h:359
#13 0x0000000008002cfd in std::allocate_shared<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>, std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> >, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > >(const std::allocator<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> > &, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > &&) (__a=...,
__args#0=...) at /usr/include/c++/8/bits/shared_ptr.h:706
#14 0x0000000008002b49 in std::make_shared<std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > >(std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > &&) (__args#0=...) at /usr/include/c++/8/bits/shared_ptr.h:722
#15 0x00000000080029c4 in std::__future_base::_S_make_async_state<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> > >(std::thread::_Invoker<std::tuple<main()::<lambda(A)>,--Type <RET> for more, q to quit, c to continue without paging--c
A> > &&) (__fn=...) at /usr/include/c++/8/future:1705
#16 0x0000000008002613 in std::async<main()::<lambda(A)>, A>(std::launch, <lambda(A)> &&, A &&) (__policy=(std::launch::async | std::launch::deferred), __fn=..., __args#0=...) at /usr/include/c++/8/future:1719
#17 0x00000000080024d3 in std::async<main()::<lambda(A)>, A>(<lambda(A)> &&, A &&) (__fn=..., __args#0=...) at /usr/include/c++/8/future:1749
#18 0x000000000800241c in main () at ./a.cpp:17
(gdb) c
Continuing.
A move
[New Thread 0x7fffff250700 (LWP 141)]
A dest
[Switching to Thread 0x7fffff250700 (LWP 141)]
Thread 2 "a.out" hit Breakpoint 1, A::A (this=0x7fffff24f98f, a=...) at ./a.cpp:9
9 A (A&& a) noexcept {std::cout<<"A move\n";};
(gdb) bt
#0 A::A (this=0x7fffff24f98f, a=...) at ./a.cpp:9
#1 0x000000000800291c in std::__invoke_impl<void, main()::<lambda(A)>, A>(std::__invoke_other, <lambda(A)> &&, A &&) (__f=..., __args#0=...)
at /usr/include/c++/8/bits/invoke.h:60
#2 0x0000000008002525 in std::__invoke<main()::<lambda(A)>, A>(<lambda(A)> &&, A &&) (__fn=..., __args#0=...) at /usr/include/c++/8/bits/invoke.h:95
#3 0x00000000080046bb in std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >::_M_invoke<0, 1>(std::_Index_tuple<0, 1>) (this=0x8022ec8) at /usr/include/c++/8/thread:244
#4 0x0000000008004642 in std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >::operator()(void) (this=0x8022ec8) at /usr/include/c++/8/thread:253
#5 0x0000000008004413 in std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>::operator()(void) const (this=0x7fffff24fdd0) at /usr/include/c++/8/future:1362
#6 0x000000000800413d in std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>(), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void> >::_M_invoke(const std::_Any_data &) (__functor=...) at /usr/include/c++/8/bits/std_function.h:283
#7 0x0000000008006067 in std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const (this=0x7fffff24fdd0)
at /usr/include/c++/8/bits/std_function.h:687
#8 0x000000000800599b in std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) (this=0x8022e90, __f=0x7fffff24fdd0, __did_set=0x7fffff24fd47) at /usr/include/c++/8/future:561
#9 0x0000000008006db3 in std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) (__f=
@0x7fffff24fd60: (void (std::__future_base::_State_baseV2::*)(std::__future_base::_State_baseV2 * const, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()> *, bool *)) 0x8005974 <std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*)>, __t=@0x7fffff24fd58: 0x8022e90, __args#0=@0x7fffff24fd50: 0x7fffff24fdd0, __args#1=@0x7fffff24fd48: 0x7fffff24fd47)
at /usr/include/c++/8/bits/invoke.h:73
#10 0x0000000008006633 in std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) (__fn=
@0x7fffff24fd60: (void (std::__future_base::_State_baseV2::*)(std::__future_base::_State_baseV2 * const, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()> *, bool *)) 0x8005974 <std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*)>, __args#0=@0x7fffff24fd58: 0x8022e90, __args#1=@0x7fffff24fd50: 0x7fffff24fdd0, __args#2=@0x7fffff24fd48: 0x7fffff24fd47)
at /usr/include/c++/8/bits/invoke.h:95
#11 0x0000000008005e30 in std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const (this=0x7fffff24fce0) at /usr/include/c++/8/mutex:672
#12 0x0000000008005e5b in std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::operator()() const (this=0x0) at /usr/include/c++/8/mutex:677
#13 0x0000000008005e6c in std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_bas--Type <RET> for more, q to quit, c to continue without paging--c
e::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::_FUN() () at /usr/include/c++/8/mutex:677
#14 0x00007fffff45e997 in __pthread_once_slow (once_control=0x8022ea8, init_routine=0x7fffff6dae20 <__once_proxy>) at pthread_once.c:116
#15 0x00000000080023bd in __gthread_once (__once=0x8022ea8, __func=0x7fffff6dae20 <__once_proxy>) at /usr/include/x86_64-linux-gnu/c++/8/bits/gthr-default.h:699
#16 0x0000000008005f05 in std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) (__once=..., __f=@0x7fffff24fd60: (void (std::__future_base::_State_baseV2::*)(std::__future_base::_State_baseV2 * const, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()> *, bool *)) 0x8005974 <std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*)>, __args#0=@0x7fffff24fd58: 0x8022e90, __args#1=@0x7fffff24fd50: 0x7fffff24fdd0, __args#2=@0x7fffff24fd48: 0x7fffff24fd47) at /usr/include/c++/8/mutex:684
#17 0x000000000800577c in std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>, bool) (this=0x8022e90, __res=..., __ignore_failure=false) at /usr/include/c++/8/future:401
#18 0x0000000008003c49 in std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>::<lambda()>::operator()(void) const (this=0x8022e90) at /usr/include/c++/8/future:1667
#19 0x000000000800431d in std::__invoke_impl<void, std::__future_base::_Async_state_impl<_BoundFn, _Res>::_Async_state_impl(_BoundFn&&) [with _BoundFn = std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >; _Res = void]::<lambda()> >(std::__invoke_other, std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>::<lambda()> &&) (__f=...) at /usr/include/c++/8/bits/invoke.h:60
#20 0x000000000800401e in std::__invoke<std::__future_base::_Async_state_impl<_BoundFn, _Res>::_Async_state_impl(_BoundFn&&) [with _BoundFn = std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >; _Res = void]::<lambda()> >(std::__future_base::_Async_state_impl<std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >, void>::<lambda()> &&) (__fn=...) at /usr/include/c++/8/bits/invoke.h:95
#21 0x0000000008004d80 in std::thread::_Invoker<std::tuple<std::__future_base::_Async_state_impl<_BoundFn, _Res>::_Async_state_impl(_BoundFn&&) [with _BoundFn = std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >; _Res = void]::<lambda()> > >::_M_invoke<0>(std::_Index_tuple<0>) (this=0x8022f08) at /usr/include/c++/8/thread:244
#22 0x0000000008004cd6 in std::thread::_Invoker<std::tuple<std::__future_base::_Async_state_impl<_BoundFn, _Res>::_Async_state_impl(_BoundFn&&) [with _BoundFn = std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >; _Res = void]::<lambda()> > >::operator()(void) (this=0x8022f08) at /usr/include/c++/8/thread:253
#23 0x00000000080048b0 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<std::__future_base::_Async_state_impl<_BoundFn, _Res>::_Async_state_impl(_BoundFn&&) [with _BoundFn = std::thread::_Invoker<std::tuple<main()::<lambda(A)>, A> >; _Res = void]::<lambda()> > > >::_M_run(void) (this=0x8022f00) at /usr/include/c++/8/thread:196
#24 0x00007fffff6dbb2f in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#25 0x00007fffff456fa3 in start_thread (arg=<optimized out>) at pthread_create.c:486
#26 0x00007fffff3794cf in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
(gdb) c
Continuing.
A move
fun
A dest
A dest
[Thread 0x7fffff250700 (LWP 141) exited]
A dest
[Inferior 1 (process 137) exited normally]
(gdb)
如我们所见:
第一步是创建调用程序 (
std::thread::__make_invoker()
)。调用程序是一种打包任务,以后可以作为一个单元执行。第二步发生在将调用程序打包到
async_state
对象并将其存储在future
(__future_base::_S_make_async_state()
)第三步发生在调用lambda时(
_State::_M_run()
)
所有这些都是实现细节,可能会在标准库的版本之间发生变化。