多线程的知识总结(8):用 thread 类 或全局 async (...) 函数,创建新线程时,谁才是在新线程里第一个被执行的函数

news2024/12/12 8:37:46

(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)

谢谢

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2258146.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

12月11日IO进程线程

作业1、创建子父进程&#xff0c;子进程将1.txt内容拷贝到2.txt中&#xff0c;父进程将3.txt内容拷贝到4.txt中。 #include <myhead.h>int main(int argc, const char *argv[]) {//创建子父进程pid_t pidfork();if(pid>0) //父进程{//打开文件1文件2int fd1open(&q…

TikTok无网络黑屏原因及解决方法

TikTok运营中最常见的问题就是出现黑屏和“Something went wrong”“No internet connection”等字样&#xff0c;这时TikTok往往已经无法正常使用&#xff0c;大大影响运营流程。那么这种情况是什么原因&#xff0c;又有什么解决办法&#xff1f; 一、无网络黑屏原因 1.‌地理…

在 Ansys Mechanical 中使用“螺栓工具”插件自动生成螺栓

总结 在有限元分析 &#xff08;FEA&#xff09; 中&#xff0c;高效创建螺栓连接对于确保机械装配的结构完整性和性能至关重要。螺栓是连接组件不可或缺的一部分&#xff0c;它们在负载下的精确建模会影响整个系统。快速高效的螺栓建模使工程师能够快速优化设计&#xff0c;满…

西门子200 smart PLC助力水处理企业自动化改造

摘要 西门子的200SMART PLC&#xff0c;以其强大的功能和灵活的应用性&#xff0c;正成为环保行业中不可或缺的一环。今天&#xff0c;我们就来看看这个小小的PLC是如何在处理环保问题中大显身手的。 不得不说&#xff0c;环保行业的痛点可不少。 比如污水处理&#xff0c;传…

【漏洞复现】CVE-2024-34102 Magento Open Source XXE漏洞

目录 漏洞介绍 影响版本 环境搭建 查看版本 漏洞复现 手动复现 漏洞 poc Magento Open Source 是一个免费开源的电子商务平台&#xff0c;适合中小企业或开发团队通过自定义代码和插件创建在线商店。它由社区开发和支持&#xff0c;功能强大但需要更多的技术投入。Adobe…

智能合约的离线签名(EIP712协议)解决方案

引言&#xff1a;本文由天玄链开源开发者提供&#xff0c;欢迎报名公益天玄链训练营 https://blockchain.163.com/trainingCamp 一、解决核心问题 项目方不支付gas费&#xff0c;由用户自己发起交易&#xff0c;用户支付gas费。用户的数据保存在链下服务器中&#xff0c;tok…

Vmware的网络适配器的NAT模式和桥接模式有何区别?如何给Uubunt系统添加桥接网卡?

Vmware的网络适配器的NAT模式和桥接模式有何区别&#xff1f; 如何给Uubunt系统添加桥接网卡? 步骤如下&#xff1a;

有源模拟滤波器的快速设计

本文章是笔者整理的备忘笔记。希望在帮助自己温习避免遗忘的同时&#xff0c;也能帮助其他需要参考的朋友。如有谬误&#xff0c;欢迎大家进行指正。 一、概述 几乎所有电子电路中都能看到有源模拟滤波器的身影。音频系统使用滤波器进行频带限制和平衡。通信系统设计使用滤波…

HarmonyOS 非线性容器TreeSet 常用的几个方法

TreeSet基于TreeMap实现&#xff0c;在TreeSet中&#xff0c;只对value对象进行处理。TreeSet可用于存储一系列值的集合&#xff0c;元素中value唯一且有序。 TreeSet和HashSet相比&#xff0c;HashSet中的数据无序存放&#xff0c;而TreeSet是有序存放。它们集合中的元素都不允…

【数据结构——查找】二分查找(头歌实践教学平台习题)【合集】

目录&#x1f60b; 任务描述 相关知识 测试说明 我的通关代码: 测试结果&#xff1a; 任务描述 本关任务&#xff1a;实现二分查找的算法。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;1.根据键盘输入的一组有序数据建立顺序表&#xff0c;2.顺序表的输…

从混沌到清晰:全面解析非结构化数据治理!

一、非结构化数据的定义 定义 非结构化数据是指不遵循固定模式或不具有预定义数据模型的数据。与结构化数据不同&#xff0c;非结构化数据没有固定的格式&#xff0c;其内容和结构通常由数据的自然形式决定。 关键特征 &#xff08;1&#xff09;多样性&#xff1a;包括文本、…

【蓝桥杯最新板】蓝桥杯嵌入式液晶上实现电子时钟

这几年蓝桥杯比赛比较适合学生技能学习&#xff0c;考虑板子功能&#xff0c;提出完成的任务。 要求在液晶完成如下图效果&#xff1a; 主要是实现液晶显示时钟和数字时钟&#xff0c;具体样式可以依据实际情况微调。 实现过程&#xff1a; 1.需要画圆&#xff08;外圆、内圆…

[WiFi] WiFi安全加密WEP Vs WPA Vs WPA2 Vs WPA3整理

WiFi安全标准时间线 WEP&#xff08;Wired Equivalent Privacy&#xff09; WEP最早于1997年推出&#xff0c;是为了保护无线网络上的数据通信而设计的。当时&#xff0c;Wi-Fi技术还处于起步阶段&#xff0c;人们开始意识到需要一种安全协议来防止未经授权的访问和窃听。WEP被…

基于微信小程序+Springboot+Vue社区超市管理系统的分析与设计(源码+lw+讲解部署等)

&#x1f497; 博主介绍✌ 3Dex&#xff08;全栈开发工程师&#xff09;&#xff0c;专注于4smile等项目的建设与优化&#xff0c;在软件开发与技术实现方面积累了丰富的经验。专注于Java、小程序、前端、Python等技术领域毕业项目实战&#xff0c;以及程序定制化开发。✌ 擅长…

亚信安全DeepSecurity完成与超云超融合软件兼容性互认

近日&#xff0c;亚信安全与超云数字技术集团有限公司&#xff08;以下简称“超云”&#xff09;联合宣布&#xff0c;亚信安全成功完成与超云超融合软件的产品兼容性互认证。经严格测试&#xff0c;亚信安全云主机安全DeepSecurity与超云FS5000增强型融合系统&#xff08;简称…

深入理解 Apache Shiro:安全框架全解析

亲爱的小伙伴们&#x1f618;&#xff0c;在求知的漫漫旅途中&#xff0c;若你对深度学习的奥秘、JAVA 、PYTHON与SAP 的奇妙世界&#xff0c;亦或是读研论文的撰写攻略有所探寻&#x1f9d0;&#xff0c;那不妨给我一个小小的关注吧&#x1f970;。我会精心筹备&#xff0c;在…

《大宋豪侠传》客户端源码 + 服务端源码 + 工具源码 + 资源,大小16.3G

《大宋豪侠传》客户端源码 服务端源码 工具源码 资源&#xff0c;大小16.3G 下载地址&#xff1a; 通过网盘分享的文件&#xff1a;【源码】《大宋豪侠传》客户端源码 服务端源码 工具源码 资源&#xff0c;大小16.3G 链接: https://pan.baidu.com/s/1lUf84LzXKB3iM7L-1P…

linux学习笔记01 基础命令

目录 创建 touch 创建文件 &#xff08;创建但是不打开&#xff09; vi / vim 创建文件 (创建一个文件并打开) mkdir 创建文件夹 切换目录 cd 查看 pwd 查看当前目录完整路径 ls 查看目录信息 dir 查看目录信息 ll 表示查看目标目录下的信息 ls -a 查看当前目录下的…

MVC基础——市场管理系统(三)Clean Architecture

文章目录 项目地址五、Clean Architecture5.1 user cage driven5.1.1创建CoreBusiness 5.2 创建UseCases5.2.1 创建CategoriesUseCases1. 创建VeiwCategoriesUseCase获取所有Cagegory 5.2.2. 实现ICategoryRepository接口3. 实现获取所有Category的方法4. 实现获取一个Cagegory…

人工智能-自动驾驶领域

目录 引言自动驾驶与人工智能的结合为什么自动驾驶领域适合发表文章博雅智信的自动驾驶辅导服务结语 引言 自动驾驶技术的崛起是当代交通行业的一场革命。通过结合先进的人工智能算法、传感器技术与计算机视觉&#xff0c;自动驾驶不仅推动了技术的进步&#xff0c;也使得未来…