Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >浅谈 Windows 编程中的 Thread

浅谈 Windows 编程中的 Thread

作者头像
Harper
发布于 2021-07-27 01:50:48
发布于 2021-07-27 01:50:48
59700
代码可运行
举报
文章被收录于专栏:Harper的碎碎念Harper的碎碎念
运行总次数:0
代码可运行

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

一些常识

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

创建线程

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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++ 来说,其实有另一个方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
_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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Windows编程(多线程)
CreateThread是一种微软在Windows API中提供了建立新的线程的函数,该函数在主线程的基础上创建一个新线程。线程终止运行后,线程对象仍然在系统中,必须通过CloseHandle函数来关闭该线程对象。
全栈程序员站长
2022/07/13
1.2K0
CreateThread 函数[通俗易懂]
改变了栈的大小,但是把CreateThread的第2参数改成0x100000或者更小的时候,程序还是会出现这样的问题,只有将栈的大小还原为默认值,且CreateThread的第2参数为0 才能正确运行
全栈程序员站长
2022/09/08
1.5K0
秒杀多线程第二篇 多线程第一次亲密接触 CreateThread与_beginthreadex本质区别
本文将带领你与多线程作第一次亲密接触,并深入分析CreateThread与_beginthreadex的本质区别,相信阅读本文后你能轻松的使用多线程并能流畅准确的回答CreateThread与_beginthreadex到底有什么区别,在实际的编程中到底应该使用CreateThread还是_beginthreadex?
全栈程序员站长
2022/09/01
2590
windows多线程(一) 创建线程 CreateThread「建议收藏」
修改说明: 这里 说了另一种创建线程方法,使用_beginthreadex()更安全的创建线程,在实际使用中尽量使用_beginthreadex()来创建线程,在博客中使用 CreateThread()l来创建线程其实是一种不太好的方法,不过这里只做原理分析,不用在实际项目中,暂且就这样吧!
全栈程序员站长
2022/09/07
4210
windows多线程(一) 创建线程 CreateThread「建议收藏」
浅谈 Windows Syscall
Windows下有两种处理器访问模式:用户模式(user mode)和内核模式(kernel mode)。用户模式下运行应用程序时,Windows 会为该程序创建一个新进程,提供一个私有虚拟地址空间和一个私有句柄表,因为私有,一个应用程序无法修改另一个应用程序的私有虚拟地址空间的数据;内核模式下,所有运行的代码都共享一个虚拟地址空间, 因此内核中驱动程序可能还会因为写入错误的地址空间导致其他驱动程序甚至系统出现错误。
意大利的猫
2021/12/20
6K1
浅谈 Windows Syscall
PE格式:新建节并插入代码
PE格式是 Windows下最常用的可执行文件格式,理解PE文件格式不仅可以了解操作系统的加载流程,还可以更好的理解操作系统对进程和内存相关的管理知识,而有些技术必须建立在了解PE文件格式的基础上,如文件加密与解密,病毒分析,外挂技术等。
微软技术分享
2022/12/24
3970
PE格式:新建节并插入代码
c语言 windows多线程_C语言 多线程
#include <process.h> // for _beginthread()
全栈程序员站长
2022/11/10
2.4K0
10年 Windows 与 Linux 程序员的区别
如果一个程序员从来没有在Linux、Unix下开发过程序,一直在Windows下面开发程序,同样是工作10年,大部分情况下与在Linux、unix下面开发10年的程序员水平会差别很大。这篇文章并不是想贬低Windows下面开发的人,做Windows开发的人看了可能会感觉不舒服,我并不是这个意思,我只是说说我自己的感受。
小小科
2018/07/31
2.2K0
10年 Windows 与 Linux 程序员的区别
PE格式:新建节并插入代码
PE格式是 Windows下最常用的可执行文件格式,理解PE文件格式不仅可以了解操作系统的加载流程,还可以更好的理解操作系统对进程和内存相关的管理知识,而有些技术必须建立在了解PE文件格式的基础上,如文件加密与解密,病毒分析,外挂技术等。
微软技术分享
2022/12/28
3200
PE格式:新建节并插入代码
QThread源码浅析[通俗易懂]
Qt版本 Qt5.6.0,下面以Windows平台为例简单研究下QThread源码实现。
全栈程序员站长
2022/09/02
5710
Windows核心编程:第6章 线程基础
Github https://github.com/gongluck/Windows-Core-Program.git //第6章 线程基础.cpp: 定义应用程序的入口点。 // #include "stdafx.h" #include "第6章 线程基础.h" #include <process.h> //线程函数 DWORD WINAPI ThreadProc(PVOID param) { return 0; } unsigned __stdcall ThreadProc2(void* p
gongluck
2018/06/22
4580
c++ 网络编程(九)TCP/IP LINUX/windows--使用IOCP模型 多线程超详细教程 以及 多线程实现服务端
原文链接:https://www.cnblogs.com/DOMLX/p/9661012.html
徐飞机
2018/09/30
3.2K0
c++ 网络编程(九)TCP/IP LINUX/windows--使用IOCP模型      多线程超详细教程 以及 多线程实现服务端
【操作系统】多线程之线程同步
定义:内核对象通过API来创建,每个内核对象是一个数据结构,它对应一块内存, 由操作系统内核分配,并且只能由操作系统内核访问。在此数据结构中少数成员如安全描述符和使用计数是所有对应都有的,但其他大多数成员都是不用类型的对象特有的。内核对象的数据结构只能由操作系统提供的API访问,应用程序在内存中不能访问。调用创建内核对象的函数后,该函数会返回一个句柄,它标识了所创建的对象。它可以由进程的任何线程使用。
半生瓜的blog
2023/05/13
5760
【操作系统】多线程之线程同步
我是一个线程(节选)
多线程编程在现代软件开发中是如此的重要,以至于熟练使用多线程编程是一名合格的后台开发人员的基本功,注意,我这里用的是基本功一词。它是如此的重要,所以您应该掌握它。本文将介绍多线程的方方面面,从基础的知识到高级进阶。让我们开始吧。
范蠡
2018/10/23
2.2K0
我是一个线程(节选)
DLL注入与安全
  安全与危险是共存的。如果我们了解危险的来源以及产生的过程,对于安全防护拥有很现实的意义。   本文主要介绍dll注入的方式,意在描述危险的来源,以及危险的执行的过程,以便于我们解决危险。
全栈程序员站长
2022/08/29
5550
DLL注入与安全
内存泄漏漫谈
对于C/C++来说,内存泄漏问题一直是个很让人头痛的问题,因为对于没有GC的语言,内存泄漏的概率要比有GC的语言大得多,同时,一旦发生问题,也严重的多,而且,内存泄漏的排查往往十分困难。对于内存泄漏,维基百科的定义是:在计算机科学中,内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。内存泄漏的原因通常情况下只能由程序源代码分析出来。如果一个程序存在内存泄
腾讯移动品质中心TMQ
2018/02/06
2.6K0
内存泄漏漫谈
1.14 手工插入ShellCode反弹
PE格式是 Windows下最常用的可执行文件格式,理解PE文件格式不仅可以了解操作系统的加载流程,还可以更好的理解操作系统对进程和内存相关的管理知识,而有些技术必须建立在了解PE文件格式的基础上,如文件加密与解密,病毒分析,外挂技术等,本次的目标是手工修改或增加节区,并给特定可执行程序插入一段ShellCode代码,实现程序运行自动反弹一个Shell会话。
微软技术分享
2023/10/11
2500
1.14 手工插入ShellCode反弹
创建线程的方式打开记事本
今天操作系统课老师讲到进程,提出了一个有趣的小实验:能否以系统调用的方式利用 Windows 创建进程的系统调用函数来打开一个软件。闲着蛋疼的我立马来了兴趣,姑且写一个玩玩(
浪漫主义狗
2023/09/20
2710
创建线程的方式打开记事本
1.14 手工插入ShellCode反弹
PE格式是 Windows下最常用的可执行文件格式,理解PE文件格式不仅可以了解操作系统的加载流程,还可以更好的理解操作系统对进程和内存相关的管理知识,而有些技术必须建立在了解PE文件格式的基础上,如文件加密与解密,病毒分析,外挂技术等,本次的目标是手工修改或增加节区,并给特定可执行程序插入一段ShellCode代码,实现程序运行自动反弹一个Shell会话。
微软技术分享
2023/09/04
2220
1.14 手工插入ShellCode反弹
C++基础语法梳理:Windows 的动态链接库
GUI(Graphical User Interface)应用,链接器选项:/SUBSYSTEM:WINDOWS
玖柒的小窝
2021/11/01
1.2K0
相关推荐
Windows编程(多线程)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验