多线程的知识总结(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)
谢谢
相关文章:

多线程的知识总结(8):用 thread 类 或全局 async (...) 函数,创建新线程时,谁才是在新线程里第一个被执行的函数
(40)用 thread 类 或全局 async (…) 函数,创建新线程时,谁才是在新线程里第一个被执行的函数? 弄清楚这个问题,有利于推测和理解线程中代码的执行流程。根据 thread 类 和 async (…࿰…...
ArcGIS地理空间平台manager存在任意文件读取漏洞
免责声明: 本文旨在提供有关特定漏洞的深入信息,帮助用户充分了解潜在的安全风险。发布此信息的目的在于提升网络安全意识和推动技术进步,未经授权访问系统、网络或应用程序,可能会导致法律责任或严重后果。因此,作者不对读者基于本文内容所采取的任何行为承担责任。读者在…...

HarmonyOS Next 元服务新建到上架全流程
HarmonyOS Next 元服务新建到上架全流程 接上篇 这篇文章的主要目的是介绍元服务从新建到上家的完整流程 在AGC平台上新建一个项目 链接 一个项目可以多个应用 AGC新建一个元服务应用 新建一个本地元服务项目 如果成功在AGC平台上新建过元服务,那么这里会自动显…...

【Linux】makefile项目管理
前言 makefile是一种自动化构建工具,广泛用于管理和编译项目,特别是在C和C等语言中。它通过定义规则来控制源代码的编译、链接和清理等过程。以下是一个基本的Makefile结构和示例,帮助你理解如何管理项目: 首先:创建…...

Lumos学习王佩丰Excel第二十一讲:经典Excel动态图表实现原理
一、动态图表实现原理 1、理解图表中的数据系列 在Excel图表中,系列指的是图表中的数据集合,它通常代表着一个数据源。每个系列都可以包含多个数据点,这些数据点在图表中以特定的形式展现,如柱状图中的柱子,折线图中…...

Linux框架(二)——pinctrl和gpio子系统
基于设备树的 LED 驱动,但是驱动的本质还是没变,都是配置 LED 灯所使用的 GPIO 寄存器,驱动开发方式和裸机基本没啥区别。 Linux 内核提供了 pinctrl 和 gpio 子系统用于GPIO 驱动,本章我们就来学习一下如何借助 pinctrl 和 gpio…...
C++ string的基本概念
文章目录 1. 什么是string?2. auto和范围for的使用2. 1 auto2. 2 范围for 3. 迭代器的概念、const string的概念3. 1 迭代器的概念3. 2 const string的概念 1. 什么是string? 在了解什么是string之前,我们首先需要知道字符串是什么。在C语言中…...

MAC虚拟机上安装WDA环境
MAC虚拟机上安装WDA环境 一、MAC虚拟机切换root权限二、macOS上安装xcode若你的macOS系统可以在appstore下载安装若你安装的macOS系统版本太低,无法在appstore上安装xcode 三、macOS上安装WebDriverAgent四、使用xcode配置WDA安装到手机上高版本系统支持 一、MAC虚拟…...

与 Cursor AI 对话编程:2小时开发报修维修微信小程序
本文记录了如何通过与 Cursor AI 对话,全程不写一行代码的情况下,完成一个完整的报修小程序。整个过程展示了 AI 如何帮助我们: 生成代码 、解决问题、优化实现、完善细节。 先看一下效果图: 一、项目配置 首先我是这样和 AI 对…...

leetcode-73.矩阵置零-day5
class Solution {public void setZeroes(int[][] mat) {int m mat.length, n mat[0].length;// 1. 扫描「首行」和「首列」记录「首行」和「首列」是否该被置零boolean r0 false, c0 false;for (int i 0; i < m; i) {if (mat[i][0] 0) {r0 true;break;}}for (int j …...

CSS学习记录13
CSS组合器 组合器是解释选择器之间关系的某种机制。CSS选择器可以包含多个简单选择器。在简单选择器之间,我们可以包含一个组合器。 CSS中有四种不同的组合器: 后代组合器(空格)子选择器(>)相邻兄弟选择器&#…...

CAD图纸加密软件哪个最好用 | 安全可靠的解决方案
CAD图纸加密软件哪个最好用 | 安全可靠的解决方案 图纸文件泄密事件频发,给企业带来了严重的商业损失、技术秘密泄露、公共安全威胁以及信誉损害。 为了应对这一挑战,选择一款既安全可靠又易于使用的CAD图纸加密软件显得尤为重要。 在众多加密软件中&a…...

基于SSM+Vue的宠物医院管理系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…...
处理VUE框架中,ElementUI控件u-table空值排序问题
按照以下步骤进行操作: 分离数据:首先,将原始数据按照username为空和非空进行分类。对非空表进行排序:对非空表按照username进行升序排序。合并表格:将空表和排序后的非空表合并,保证空表挂接在排序后的非…...

专业140+总分400+北京理工大学826信号处理导论考研经验北理工电子信息与通信工程,真题,大纲,参考书。
考研总分400,专业826信号处理导论(信号与系统和dsp)140,成功上岸北理工,虽然已经一段时间,但是后劲很大,每每回想还是昨日事,群里同学多次要求分享自己的一些经验,感谢大…...
Rocky DEM tutorial5_Drop Weight test_落锤试验
tutorial5_Drop Weight test_落锤实验 文章目录 tutorial5_Drop Weight test_落锤实验0. 目的1. 模型介绍2. 模型设置2.1 设置Physics2.2 导入几何2.3 定义进口面2.4 设置motion frames2.5 设置边界条件2.6 设置材料2.7 设置 materials interactions2.8 设置 Particles2.9 设置…...

C#,在 C# 语言中将 LaTeX 转换为 PNG 或 JPG 图像
在 C 语言中将 LaTeX 转换为 PNG 或 JPG 图像# 12月 28, 2021 2 分钟 法尔汉拉扎 在 C 语言中将 TeX 转换为 PNG JPG 图像# TeX 格式用于处理技术和科学文件。它通常用于交流或发布此类文档。在某些情况下,您可能需要将 TeX 文件渲染为 PNG 或 JPG 等图像…...
Elasticsearch:Mapping-映射
一、创建索引 自动生成索引字段数据类型即自动映射 创建之前,先删除索引防止重复创建 删除索引: DELETE product_mapping创建索引 product_mapping并且赋值 PUT /product_mapping/_doc/1 {"name": "xiaomi phone","desc": "s…...
安装Tensorflow@FreeBSD(失败)
pkg 安装,失败,找不到:pkg: No packages available to install matching science/py-tensorflow have been found in the repositories ports安装 cd /usr/ports/science/py-tensorflow make install 报错: 按照提示重新发命令 make DISABLE_VULNERA…...

API接口示例:电商商品评论数据
当然,以下是一个简化的电商商品评论数据API接口的示例。请注意,这只是一个示例,实际的API接口可能会更加复杂,并且会包含更多的验证、错误处理和安全措施。 API接口示例:电商商品评论数据 基础信息 API名称…...

Qt/C++学习系列之Excel使用记录
Qt/C学习系列之Excel使用记录 前言The process was ended forcefully.解决方式断点查语句问题 总结 前言 在项目中解析条目达50多条,并且都需要将对应的结果进行显示。为了将结果显示的更加清晰,考虑采用QTableWidget进行表格设置,而在使用过…...

GOOUUU ESP32-S3-CAM 果云科技开发板开发指南(一)(超详细!)Vscode+espidf 通过摄像头拍摄照片并存取到SD卡中,文末附源码
看到最近好玩的开源项目比较多,就想要学习一下esp32的开发,目前使用比较多的ide基本上是arduino、esp-idf和platformio,前者编译比较慢,后两者看到开源大佬的项目做的比较多,所以主要学习后两者。 本次使用的硬件是GO…...

【Java微服务组件】分布式协调P4-一文打通Redisson:从API实战到分布式锁核心源码剖析
欢迎来到啾啾的博客🐱。 记录学习点滴。分享工作思考和实用技巧,偶尔也分享一些杂谈💬。 有很多很多不足的地方,欢迎评论交流,感谢您的阅读和评论😄。 目录 引言Redisson基本信息Redisson网站 Redisson应用…...
蓝桥杯单片机之通过实现同一个按键的短按与长按功能
实现按键的短按与长按的不同功能 问题分析 对于按键短按,通常是松开后实现其功能,而不会出现按下就进行后续的操作;而对于按键长按,则不太一样,按键长按可能分为两种情况,一是长按n秒后实现后续功能&…...

基于VMD-LSTM融合方法的F10.7指数预报
F10.7 Daily Forecast Using LSTM Combined With VMD Method F10.7 solar radiation flux is a well-known parameter that is closely linked to solar activity, serving as a key index for measuring the level of solar activity. In this study, the …...

基于J2EE架构的在线考试系统设计与实现【源码+文档】
目录 摘要: Abstract: 1 引言 2 在线考试系统构架 2.1 在线考试系统一般需求分析 2.2 当前在线考试系统现状分析 2.3 基于J2EE的在线考试系统架构介绍及拥有的优势 2.3.1 结构总体介绍 2.3.2 客户层组件 2.3.2.1 Applets 2.3.2.2 应用程序客户端 2.3.3 …...
【Go语言基础【5】】Go module概述:项目与依赖管理
文章目录 一、Go Module 概述二、Go Module 核心特性1. 项目结构2. 依赖查找机制 三、如何启用 Go Module四、创建 Go Module 项目五、Go Module 关键命令 一、Go Module 概述 Go Module 是 Go 1.11 版本(2018 年 8 月)引入的依赖管理系统,用…...
用设计模式重新思考(类FSM)验证:从混乱到优雅
在数字设计的世界里,Finite-State Machine(FSM)就像一个城市的交通信号系统。每个状态都有自己的规则,每个转换都需要精确的条件。而对于验证工程师来说,如何优雅地验证这些状态机,一直是个让人头疼的问题。…...
centos查看开启关闭防火墙状态
执行:systemctl status firewalld ,即可查看防火墙状态 防火墙的开启、关闭、禁用命令 (1)设置开机启用防火墙:systemctl enable firewalld.service (2)设置开机禁用防火墙:system…...

【MATLAB去噪算法】基于CEEMDAN联合小波阈值去噪算法(第四期)
CEEMDAN联合小波阈值去噪算法相关文献 一、EMD 与 EEMD 的局限性 (1)EMD (经验模态分解) 旨在自适应地将非线性、非平稳信号分解成一系列 本征模态函数 (IMFs),这些 IMFs 从高频到低频排列。 核心问题:模态混合 (Mode Mixing) 同…...