小解_beginthreadex与_beginthreadex和CreateThread的区别
Posted _Flame
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了小解_beginthreadex与_beginthreadex和CreateThread的区别相关的知识,希望对你有一定的参考价值。
为什么用_beginthreadex而不用CreateThread函数
原因:
1.主要考虑的是线程上下文的切换,如果一个线程设置了全局变量erron 此时它的执行挂起或者中断了,进程执行其他线程去了
正好它调用了C/C++运行库创建了相同名字的全局变量,拿回来后之前的全局变量改了值就会出错,所以我们最好用局部变量,
线程需要自己的一个自己的数据结构去存储这个全局变量这样其他线程改变时影响不到它,这恰恰就是_BeginThreadex的优点
创建时候会创建自己的数据块_tiddata而且_BeginThreadex调用的内部函数是CreateThread(因为windows只认识他创建线程),
CreateThreaad函数被调用的时候传给它的函数地址是_threadstartex不是pfnstartAddr,参数的地址是_tddata结构的地址,
不是Param,如果一切顺利会返回,就会返回线程的句柄,失败就是0
CreateThread也可以创建数据块为什么不能用呢,最后看
2._beginThreadex注意:
每个线程都有自己专有的_tiddata数据块,他们呢是从c\\c++运行库堆上分配的 记住线程栈是从进程地址空间分配的
传给_beginThreadex的线程函数的地址保存在_tiddata内存块中
_BeginThreadex的优点有自己的数据块而且_BeginThreadex调用的内部函数是CreateThread(因为windows只认识他创建线程)
2.1
_threadstartex的注意:
新线程收先执行的RtlUserThreadStart在跳转到_threadstartex
2.1.1._threadstartex的唯一参数是_tiddata内存块的地址
2.1.2.利用TlsSetValue把_tiddata内存块和_threadstartex地址于线程关联起来存到线程局部存储里面成为它的私有属性
2.1.3.CreateThreaad函数被调用的时候传给它的函数地址是_threadstartex不是pfnstartAddr,参数的地址是_tddata结构的地址,不是Param
!!!一句话_beginThreadex会调用_threadstartex把_tiddata内存块保存在TLS中,在_threadstartex里的_callthreadstartex中从TLS中取出
_threadstartex函数设置_tiddata内存块和_threadstartex地址到TLS,_callthreadstartex取出使用,调用保存在_tiddata中由外部程序员提供的线程入口函数,并传入保存在_tiddata中的参数然后传值给CreateThreaad建立起线程
等待线程的结束,当线程返回时,调用_endthreadex函数,在_endthreadex内部通过_getptd_noxeit函数获得_tiddata结构对象然后利用_freeptd释放掉_tiddata结构的内存
。_endthreadex函数最终会调用系统的ExitThread。
对于_endthreadex函数如下
C运行库还给函数设置了同步对象 例如两个线程不能同时用malloc,一个线程malloc时候另一个只能等待
最终为什么为什么用_beginthreadex而不用CreateThread函数呢?
因为CreateThread第一个无法处理singal函数(该函数用于设置中断信号处理函数,比如可以使用此函数屏蔽CTRL+C,更多介绍可参阅MSDN),
它没有像在_callthreadstartex里的SEH处理结构化异常和singal函数
第二个无法处理_tiddata内存块的销毁,因为他不能用_endthreadex释放_tiddata内存块呀 (CreateThread不会在创建线程之前申请一个_tiddata结构内存块,当一个线程调用一个需要_tiddata结构的C/C++运行库函数(例如errno, strtok, _gmtime等)时,虽然C/C++运行库函数会为主调函数申请并初始化一个_tiddata块,但是在线程退出的时候,如果不是调用_endthreadex函数的话,_tiddata块将不能被释放,从而导致内存泄露。(这里会有一个例外))如下
当模块链接到C/C++运行库的DLL版本时,这个库(例如VS2008的msvcr90d.dll,msvcr90.dll)会在线程终止时收到一个DLL_THREAD_DETACH通知,然后会执行释放_tiddata块(如果有申请)。虽然这是可以防止_tiddata块内存泄露的,但仍然强烈建议使用_beginthreadex来创建线程,而不要使用CreateThread。因为不能保证所有使用者都使用动态链接库版本。
以上是关于小解_beginthreadex与_beginthreadex和CreateThread的区别的主要内容,如果未能解决你的问题,请参考以下文章
转载CreateThread与_beginthreadex本质区别
秒杀多线程第二篇 多线程第一次亲密接触 CreateThread与_beginthreadex本质区别
秒杀多线程第二篇 多线程第一次亲密接触 CreateThread与_beginthreadex本质区别