当前位置: 首页 > wzjs >正文

哈尔滨网站建设美丽wordpress防站

哈尔滨网站建设美丽,wordpress防站,网站免费建站系统,做ppt的图片素材网站Thread 本节我们来详细介绍一下c中的线程类thread&#xff0c;在讲解的过程中会用到大量模板的知识&#xff0c;可以去看c详解模板泛型编程&#xff0c;详解类模板的实现为什么不能放在cpp文件_泛型函数 cpo-CSDN博客 源码: template <class _Fn, class... _Args, enable_…

Thread

本节我们来详细介绍一下c++中的线程类thread,在讲解的过程中会用到大量模板的知识,可以去看c++详解模板泛型编程,详解类模板的实现为什么不能放在cpp文件_泛型函数 cpo-CSDN博客
源码:

template <class _Fn, class... _Args, enable_if_t<!is_same_v<_Remove_cvref_t<_Fn>, thread>, int> = 0>
_NODISCARD_CTOR_THREAD explicit thread(_Fn&& _Fx, _Args&&... _Ax) {_Start(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...);
}template <class _Tuple, size_t... _Indices>
static unsigned int __stdcall _Invoke(void* _RawVals) noexcept{const unique_ptr<_Tuple> _FnVals(static_cast<_Tuple*>(_RawVals));_Tuple& _Tup = *_FnVals.get();_STD invoke(_STD move(_STD get<_Indices>(_Tup))...);_Cnd_do_broadcast_at_thread_exit();return 0;
}template <class _Tuple, size_t... _Indices>
_NODISCARD static constexpr auto _Get_invoke(index_sequence<_Indices...>) noexcept {return &_Invoke<_Tuple, _Indices...>;
}
template <class _Fn, class... _Args>
void _Start(_Fn&& _Fx, _Args&&... _Ax) {using _Tuple                 = tuple<decay_t<_Fn>, decay_t<_Args>...>;auto _Decay_copied           = _STD make_unique<_Tuple>(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...);constexpr auto _Invoker_proc = _Get_invoke<_Tuple>(make_index_sequence<1 + sizeof...(_Args)>{});_Thr._Hnd = reinterpret_cast<void*>(_CSTD _beginthreadex(nullptr, 0, _Invoker_proc, _Decay_copied.get(), 0, &_Thr._Id));if (_Thr._Hnd) {(void) _Decay_copied.release();} else {_Thr._Id = 0;_Throw_Cpp_error(_RESOURCE_UNAVAILABLE_TRY_AGAIN);}
}

enable_if_t<!is_same_v<_Remove_cvref_t<_Fn>, thread>, int> = 0是一个 SFINAE(Substitution Failure Is Not An Error)技巧,用于禁止使用thread对象作为可调用对象来构造新的thread对象。

我们从thread的构造函数开始,一步一步讲解线程的启动,构造函数会直接将接受的参数完美转发给_Start函数,这个函数会将传入的函数与参数进行包装,最后调用系统提供的线程函数来启动线程,此函数会将所有内容放入一个元组(_Tuple)中,具体类型是tuple<decay_t<_Fn>, decay_t<_Args>…>,这里的decay_t会对参数进行退化处理,它会移除引用、constvolatile 限定符,并且把数组类型转换为指针类型,函数类型转换为函数指针类型。之后使用make_unique构造了一个_Tuple对象,内部包含了退化后的可调用对象与所有参数。
这里需要注意_Get_invoke函数返回的是一个函数指针,它返回的不是_Invoke函数的返回值,而是_Invoke<_Tuple, _Indices...>这个函数的指针,返回的这个函数指针用于后续_beginthreadex函数的调用,调用_Get_invoke使用make_index_sequence在编译器生成了一个整数序列,这个生成的整数序列会被传递给 index_sequence<_Indices...>,并通过模板参数展开将索引保存在 _Indices 中,这里用于展开元组。
本教程使用的是Windows11所以标准库使用了Windows的线程api,_beginthreadex函数接受了我们的可调用对象与参数,参数传入的是元组这回在后续的_Invoke函数中展开,_beginthreadex 函数返回的是一个 uintptr_t 类型的值,它实际上是一个无符号整数类型,用于表示线程句柄。而 _Thr._Hnd 是一个 void* 类型的变量,用于存储线程句柄。因此,这就需要使用 reinterpret_cast<void*> 将 _beginthreadex 返回的 uintptr_t 类型的值转换为 void* 类型,以便赋值给 _Thr._Hnd。传递&_Thr._Id的目的是获得线程id
reinterpret_cast 是 C++ 中的一种强制类型转换运算符,它主要用于将一种指针类型转换为另一种指针类型,甚至可以在不同类型的指针和整数类型之间进行转换。reinterpret_cast 提供了最底层、最直接的类型转换,它不进行任何类型检查或数据转换,只是简单地将二进制位从一种类型解释为另一种类型。
后续会检测线程创建成功,我们让_Decay_copied放弃其管理的资源,以免_Start运行完成后释放元组,如果不成功会将线程id置为0并抛出错误异常

最后我们来介绍一下调用函数_Invoke,它接受一个void*的参数(这就是我们的元组),这个参数是_beginthreadex传递给它的,首先通过static_cast将void*转换会元组类型,之后通过_STD get<_Indices>(_Tup) 借助索引 _Indices 从元组 _Tup 中获取元素。_Indices 是一个编译时生成的整数序列,通过参数包展开,能够依次获取元组中的所有元素,然后把这些元素传递给 std::invoke 调用的可调用对象。
_Cnd_do_broadcast_at_thread_exit 是一个内部函数,它的作用是在当前线程退出时广播一个条件变量。这通常用于线程同步,确保在某个线程退出时通知其他等待的线程。

invoke与get函数

std::invoke 是 C++17 引入标准库的一个通用调用工具,其用途是统一地调用可调用对象,像函数、函数指针、成员函数指针、成员对象指针、函数对象(重载了 operator() 的类实例)等,并且会把相应的参数传递给这些可调用对象。
std::invoke 会依据可调用对象的类型和参数的情况,采用合适的方式来调用可调用对象。例如,对于普通函数,它会直接调用;对于成员函数指针,它会正确处理对象实例的绑定。

std::get 是用于访问元组(std::tuple)、std::pair 或者 std::array 元素的函数模板,它能依据索引或者类型来获取容器中的元素。

_beginthreadex

函数原型如下:

uintptr_t _beginthreadex(void* security,unsigned stack_size,unsigned (__stdcall* start_address)(void*),void* arglist,unsigned initflag,unsigned* thrdaddr
);
  1. security
    • 类型:void*
    • 含义:指向一个 SECURITY_ATTRIBUTES 结构体的指针,该结构体用于指定新线程的安全属性。如果传入 NULL,表示使用默认的安全属性。通常情况下,我们传入 NULL 即可。
  2. stack_size
    • 类型:unsigned
    • 含义:指定新线程的堆栈大小,以字节为单位。如果传入 0,则表示使用默认的堆栈大小。
  3. start_address
    • 类型:unsigned (__stdcall*)(void*)
    • 含义:指向新线程启动函数的指针。这个函数是新线程开始执行的入口点,它必须遵循 __stdcall 调用约定,返回类型为 unsigned,并且接受一个 void* 类型的参数。__stdcall 是一种调用约定,规定了参数传递的顺序(从右到左)和栈的清理方式(由被调用函数清理)。
  4. arglist
    • 类型:void*
    • 含义:传递给新线程启动函数的参数。这个参数会被作为 void* 类型传递给 start_address 所指向的函数。如果不需要传递参数,可以传入 NULL
  5. initflag
    • 类型:unsigned
    • 含义:指定新线程的初始状态。可以传入以下值:
      • 0:线程创建后立即开始执行。
      • CREATE_SUSPENDED:线程创建后处于挂起状态,需要调用 ResumeThread 函数来启动线程。
  6. thrdaddr
    • 类型:unsigned*
    • 含义:指向一个 unsigned 类型的变量,用于接收新线程的线程 ID。如果不需要获取线程 ID,可以传入 NULL
      如果线程创建成功,_beginthreadex 函数返回一个新线程的句柄,类型为 uintptr_t。这个句柄可以用于后续对线程的操作,如等待线程结束、终止线程等。如果线程创建失败,函数返回 0

_Thrd_t结构体

接下来我们再看看thread中的一个结构体_Thr,他是定义在下面:

extern "C" {
using _Thrd_id_t = unsigned int;
struct _Thrd_t { // thread identifier for Win32void* _Hnd; // Win32 HANDLE_Thrd_id_t _Id;
};
}

_Thrd_t 结构体用于封装 Windows 线程的相关信息,包括线程句柄(_Hnd)和线程 ID(_Id)。通过这个结构体,可以方便地管理和操作线程,例如在创建线程时保存线程句柄和线程 ID,在后续的操作中使用这些信息来控制线程的行为。
这里将 _Thrd_t 结构体定义为 C 语言风格(使用 extern "C" 块)主要是为了实现与 C 语言代码的兼容性。_beginthreadex 是 Windows C 运行时库提供的函数,它遵循 C 语言的调用约定和命名规则。使用 extern "C" 可以确保 _Thrd_t 结构体在编译时生成的符号名遵循 C 语言的规则,从而可以与 C 语言代码无缝交互。

decay_t的主要作用

当创建线程时,参数需要被 安全地复制或移动 到线程的独立存储空间中,避免因原始参数生命周期结束(如局部变量被销毁)导致的悬空引用或指针问题。std::decay_t 的作用包括:移除引用:将 T& 或 T&& 退化为 T,强制生成值的副本(而非保留引用)。 处理数组和函数指针:将数组类型 T[N] 退化为 T*,函数类型 F(Args...) 退化为 F(*)(Args...),使其可复制。
这使得 std::thread 构造函数能统一处理函数指针、函数对象或 lambda,确保线程内部操作的是独立的值,确保不会出现悬挂引用的问题。


文章转载自:

http://blD1Dz1h.fhrgk.cn
http://Y1SdbR47.fhrgk.cn
http://0UcRguzL.fhrgk.cn
http://TOBErDbJ.fhrgk.cn
http://lqIUvjDo.fhrgk.cn
http://spXE0Utx.fhrgk.cn
http://VCslfliu.fhrgk.cn
http://ahqKwJfR.fhrgk.cn
http://vbf11EUG.fhrgk.cn
http://DeAzuLJM.fhrgk.cn
http://GczODYOV.fhrgk.cn
http://NIYdmc0j.fhrgk.cn
http://1WWzU3Po.fhrgk.cn
http://b06BrS5n.fhrgk.cn
http://mCQ1pKdT.fhrgk.cn
http://Vy9jM5Sj.fhrgk.cn
http://tiiGuFzR.fhrgk.cn
http://xqYQyW0q.fhrgk.cn
http://KvNSHUfQ.fhrgk.cn
http://5QRQFTnX.fhrgk.cn
http://QtxUvezd.fhrgk.cn
http://M6BrHGS0.fhrgk.cn
http://YMTDgKsb.fhrgk.cn
http://880s0m1J.fhrgk.cn
http://hJs86z1C.fhrgk.cn
http://nIQ9l1Qv.fhrgk.cn
http://SVZ3yOeJ.fhrgk.cn
http://JmSwTfIp.fhrgk.cn
http://DaAr55vY.fhrgk.cn
http://DgaUdugx.fhrgk.cn
http://www.dtcms.com/wzjs/758291.html

相关文章:

  • 信息管理系统网站模板企业网站建设要多久
  • 国外网站可以访问吗WordPress页面加分类文章
  • 台州手机端建站模板简单详细搭建网站教程
  • 网站建设ppt百度文库网络营销的常用策略
  • 手机制作网站的软件体育视频网站建设
  • 宁波网站建设的过程实施网站推广的最终目的
  • 跨境商城网站建设营销推广的方法
  • 长春 做网站多少钱2一3万元小型加工设备
  • 如何对网站做进一步优化wordpress模板制作
  • 东莞市环保局网站如何做登记表衡阳网站页面设计公司
  • 深喉咙企业网站系统广西建筑模板
  • 高清网站seo网站建设与管理教学方案
  • 怎么样自己做一个网站精准客户截流软件
  • 做我女朋友套路网站网易企业邮箱满了怎么办
  • 海外网站服务器租用2022中国进入一级战备了吗
  • 东莞专业网站建设价钱网站建设与管理实践收获
  • 青岛公路建设集团网站网线制作标准
  • 医院诊所网站源码WordPress不收录首页
  • 娄底市住房和城乡建设局网站网站代码的重点内容是什么
  • 网站左侧图片悬浮代码国际新闻最新消息今天新闻大事件视频
  • 网站调优做网站界面
  • 长沙网站自己制作网站备案哪个局管
  • 充值网站制作网上销售平台有哪些
  • 西宁做网站_君博示范宁波建设网站公司推荐
  • 温州做网站哪家好阳江房地产信息网
  • 化妆品网站建设推广方案企业站模板
  • 做ppt音乐模板下载网站深圳约的网站设计
  • 为什么要推行政务公开网站建设采集文章留在网站
  • 网站推广与品牌建设上海到北京多远
  • 关于网站建设的网站wordpress音乐盒