前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >浅谈 Windows 编程中的 Thread

浅谈 Windows 编程中的 Thread

作者头像
Harper
发布2021-07-27 09:50:48
5100
发布2021-07-27 09:50:48
举报

线程对于 Windows 编程人员来说,并不陌生,但是一直以来,我对它的了解也只是基本的使用层面。对于很多细节,也并不是很了解。这作为一个 Windows 客户端开发人员,可以说是非常尴尬了。所以,抽了一点时间,仔细梳理了一下线程相关的内容。顺便记录下来。

一些常识

  • 基本状态:就绪,执行,阻塞
  • 堆公有、栈私有
  • 创建和结束所需要的系统开销:小
  • 没有自己的地址空间

创建线程

在 Windows 下创建一个线程,很自然的会想到

CreateThread(
    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
    _In_ SIZE_T dwStackSize,
    _In_ LPTHREAD_START_ROUTINE lpStartAddress,
    _In_opt_ __drv_aliasesMem LPVOID lpParameter,
    _In_ DWORD dwCreationFlags,
    _Out_opt_ LPDWORD lpThreadId
    );

这个方法可以说对 Windows 应用开发人员并不陌生。当使用这个方法的时候,在平时使用的时候,比较多关注的就是lpStartAddresslpParameter。这是线程函数的入口以及参数。创建一个新线程之后,将会从这里开始执行。

但是对于 C++ 来说,其实有另一个方法

_ACRTIMP uintptr_t __cdecl _beginthreadex(
    _In_opt_  void*                    _Security,
    _In_      unsigned                 _StackSize,
    _In_      _beginthreadex_proc_type _StartAddress,
    _In_opt_  void*                    _ArgList,
    _In_      unsigned                 _InitFlag,
    _Out_opt_ unsigned*                _ThrdAddr
    );

在这里,_StartAddress_ArgList则跟上述那两个参数是类似的作用。 然而在这两个方法的选择中,《Windows 核心编程》早有公断。

根据作者的说法是选择_beginthreadex替代CreateThread。而原因则要从_beginthreadex的实现上说起。

_beginthreadex在 Windows 下的实现也是调用了CreateThread,毕竟在 Windows 系统中,只认这一种创建线程的方式。但是在这之前,它还会做一些额外工作。创建一个线程数据块( tiddata ),然后将入口和参数都保存到数据块中,最后还要把数据块保存在 TLS 中。之后还要初始化一个 SEH 帧,用来处理运行时产生的错误。然后在线程结束之前,释放掉 tiddata 。那这样看,确实要比CreateThread多做一些事情。

话说回来,如果不做这些事情,当然就会有问题。比较直接的问题就是内存泄漏。原因是,如果使用CreateThread创建线程,当调用一些运行库函数的时候,会检查这个 tiddata 。如果发现没有,则会自己搞出一个,而这个在线程结束的时候,就不会被正确释放,就出现了内存泄漏。

类似errno这种运行库函数,需要反应正确的错误信息,如果不记录线程相关信息,则会在多线程的时候出现错误,所以一个 tiddata 是必要的,这也说明了为什么这个 tiddata 无论什么情况都会存在。

所以综上所述,在创建线程是,应该选择_beginthreadex

关于更详细的_beginthreadex内容,参考 _beginthread, _beginthreadex 这篇文章是最好了

TLS

上边说的 TLS。可谓是线程中不可缺少的东西。因为线程之间是共享地址空间的,所以当有一些每个线程自己所需要的数据的时候,就不那么方便。而 TLS 就是用来解决这个问题。存储在 TLS 中的数据,对于每个线程之间,是互相隔离的。

结束线程

尽可能的让线程执行完自然结束。不到万不得已的时候,都不要使用ExitThread或者是_endthreadex。因为会使主调线程不正常返回,导致构造的 C++ 对象都不会析构;如果使用ExitThread还会造成 tiddata 不会被释放。

后记

关于多线程编程其实坑不算少,唯有对 Thread 多一些了解,才能写出更高质量的代码。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-08-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一些常识
  • 创建线程
  • TLS
  • 结束线程
  • 后记
相关产品与服务
SSL 证书
腾讯云 SSL 证书(SSL Certificates)为您提供 SSL 证书的申请、管理、部署等服务,为您提供一站式 HTTPS 解决方案。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档