多线程的知识总结(8):用 thread 类 或全局 async (...) 函数,创建新线程时,谁才是在新线程里第一个被执行的函数
(40)用 thread 类 或全局 async (…) 函数,创建新线程时,谁才是在新线程里第一个被执行的函数?
弄清楚这个问题,有利于推测和理解线程中代码的执行流程。根据 thread 类 和 async (…)函数的源码实现,得到的结论是:各个线程拥有独立的栈空间来执行函数,存储函数的局部变量。但各个线程共用进程的堆空间。所以通过指向堆区的指针,各个线程之间可以实现数据的传递与共享。其实在堆区保存的是 tuple 元组,该 tuple 可以保存各种类型的数据:函数与其参数。新线程中启动的 c++ 全局函数 invoke(…) 会解析该 tuple 元组,并调用里面的函数。从而把咱们程序员指定的函数在新线程中运行起来。下面根据源代码举例说明。
(41) thread 类的创建新线程流程:
++ 以下也给出其源码版:
template <class _Fn, class... _Args, enable_if_t<!is_same_v<_Remove_cvref_t<_Fn>, thread>, int> = 0>
thread(_Fn&& _Fx, _Args&&... _Ax) { _Start( forward<_Fn>(_Fx), forward<_Args>(_Ax)...); }
template <class _Fn, class... _Args> void _Start(_Fn&& _Fx, _Args&&... _Ax)
{
using _Tuple = tuple<decay_t<_Fn>, decay_t<_Args>...>;
auto _Decay_copied = make_unique<_Tuple>(forward<_Fn>(_Fx), forward<_Args>(_Ax)...);
auto _Invoker_proc = _Get_invoke<_Tuple>(make_index_sequence<1 + sizeof...(_Args)>{});
// u_long _beginthreadex( void* security, u_long stack_size, u_long (* start_address)(void*),
_Thr._Hnd = reinterpret_cast<void*>( //void* arglist, u_long initflag, u_long* thrdaddr );
_CSTD _beginthreadex(nullptr, 0, _Invoker_proc, _Decay_copied.get(), 0, &_Thr._Id));
}
template <class _Tuple, size_t... _Indices> // 本函仅仅是返回上面的函数的地址
static auto _Get_invoke(index_sequence<_Indices...>) { return &_Invoke<_Tuple, _Indices...>; }
template <class _Tuple, size_t... _Indices> static unsigned int _Invoke(void* _RawVals)
{ // 先把形参的 void* 指针转换为有意义的指针类型
unique_ptr<_Tuple> _FnVals(static_cast<_Tuple*>(_RawVals)); _Tuple& _Tup = *_FnVals;
_STD invoke(_STD move(_STD get<_Indices>(_Tup))...); return 0;
}
(42)创建新线程,还有另一种方式,就是使用 async(…)函数。这种方式,创建新线程,又是哪一个函数最先被执行呢:
++ 这里再给出代码版本:
template <class _Ret, class... _ArgTypes>
class _Packaged_state<_Ret& (_ArgTypes...)> : public _Associated_state<_Ret*> {
private: function<_Ret& (_ArgTypes...)> _Fn; // 包含了一个 function 对象以容纳各种可调用对象
public : template <class _Fty2> // 有参构造函数
_Packaged_state(_Fty2&& _Fnarg) : _Fn(_STD forward<_Fty2>(_Fnarg)) {}
void _Call_immediate(_ArgTypes... _Args)
{
this->_Set_value( addressof( _Fn( forward<_ArgTypes>(_Args)...) ), false);
}
};
template <class _Rx>
class _Task_async_state : public _Packaged_state< _Rx() > { // 此处指明了封装的函数类型 R()
private: ::Concurrency::task<void> _Task; // 这是要新建线程对象
public : using _Mybase = _Packaged_state<_Rx()>; // 简写父类,同时指出被调函数是无参函数
template <class _Fty2> // 有参构造函数
_Task_async_state(_Fty2&& _Fnarg) : _Mybase(_STD forward<_Fty2>(_Fnarg))
{
_Task = ::Concurrency::create_task( [this]() { this->_Call_immediate(); } );
}
};
//*************************************************************************************************
template <class _Ret, class _Fty>
_Associated_state<typename _P_arg_type<_Ret>::type>* // 返回值
_Get_associated_state(launch _Psync, _Fty&& _Fnarg) {
switch (_Psync) {
case launch::async:
default : return new _Task_async_state<_Ret>(_STD forward<_Fty>(_Fnarg)); }
} // 模板参数 _Fty 就是 _Fake_no_copy_callable_adapter<T...> 类型,包含被调函数及其实参的 tuple 元组
template <class _Fty, class... _ArgTypes>
future<_Invoke_result_t<decay_t<_Fty>, decay_t<_ArgTypes>...>> // 函数返回值
async(launch _Policy, _Fty&& _Fnarg, _ArgTypes&&... _Args)
{ // 简写函数的返回值类型,并对函数的返回值的类型进行必要的转换。
using _Ret = _Invoke_result_t<decay_t<_Fty>, decay_t<_ArgTypes>...>;
using _Ptype = typename _P_arg_type<_Ret>::type;
_Promise<_Ptype> _Pr(_Get_associated_state<_Ret>(_Policy,
_Fake_no_copy_callable_adapter<_Fty, _ArgTypes...>( forward<_Fty>(_Fnarg), forward<_ArgTypes>(_Args)...)
));
return future<_Ret>(_Pr._Get_state_for_future(), _Nil());
} // 调用了 future 的某版本的构造函数
//**************************************************************************************************************
template <class... _Types> // 本类型是一个可调用对象
class _Fake_no_copy_callable_adapter //核心是包括了一个 tuple 元组
{
public: using _Storaget = tuple<decay_t<_Types>...>; mutable _Storaget _Storage;
_Fake_no_copy_callable_adapter(_Types&&... _Vals) : _Storage( forward<_Types>(_Vals)...) {}
auto operator()() -> decltype(_Invoke_stored( move( declval<_Storaget&>()) ) )
{ return _Invoke_stored(_STD move(_Storage)); }
};
template <class... _Types>
auto _Invoke_stored(tuple<_Types...>&& _Tuple) // invoke() a tuple
-> decltype(_Invoke_stored_explicit(_STD move(_Tuple), index_sequence_for<_Types...>{}))
{ return _Invoke_stored_explicit(_STD move(_Tuple), index_sequence_for<_Types...>{}); }
template <class... _Types, size_t... _Indices> // invoke() a tuple with explicit parameter ordering
auto _Invoke_stored_explicit(tuple<_Types...>&& _Tuple, index_sequence<_Indices...>)
-> decltype(_STD invoke(_STD get<_Indices>(_STD move(_Tuple))...))
{ return _STD invoke(_STD get<_Indices>(_STD move(_Tuple))...); }
(43)
谢谢
原文地址:https://blog.csdn.net/zhangzhangkeji/article/details/144404780
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!