多线程学习-线程创建与销毁摘录

多线程知识点摘录(网络资源,个人学习摘录)


<拜读的博文>
_beginThreadex的用法 
http://blog.163.com/tfn2008@yeah/blog/static/1103213192012641036579/


_beginthreadex与createthread和AfxBeginThread的区别 
http://blog.sina.com.cn/s/blog_69b45b950100kaxb.html


秒杀多线程第二篇 多线程第一次亲密接触 CreateThread与_beginthreadex本质区别
http://blog.csdn.net/morewindows/article/details/7421759


vc中调用TerminateThread终止线程所导致的死锁问题
http://blog.csdn.net/shanzhizi/article/details/7731821

</拜读的博文>




<!-- ---------------------------摘录内容---------------------- -->
<!-- -------------------Window下的多线程创建与销毁C++函数问题---------------------- -->
<线程的创建>


关于_beginthreadex和CreateThread的区别
 
CreateThread是Win32 API 中创建线程的基本函数; _beginthread(ex) 是C++ 运行库的函数。为什么要有两个呢?因为C++ 运行库里面有一些函数使用了全局量,如果使用 CreateThread() 时使用这些C++ 运行库的函数,就会出现不安全的问题(没有保护的全局量)。而 _beginthreadex 为这些全局变量做了处理,使得每个线程都有一份独立
的“全局”量。




CreateThread是Windows的API函数,提供操作系统级别的创建线程的操作,且仅限于工作者线程。在使用的过程中要考虑到进程的同步与互斥的关系(防止死锁)。线程函数定义为:DWORD WINAPI ThreadFun(LPVOID pParameter)。但它没有考虑:
(1)C Runtime库中需要对多线程进行纪录和初始化,以保证C函数库工作正常(典型的例子是strtok函数)。
(2)MFC也需要知道新线程的创建,也需要做一些初始化工作(当然,如果没用MFC就没事了)。
所以:不调用MFC和RTL(运行时库)的函数时,可以用CreateThread,其它情况不要轻易使用




_beginthreadex:MS对C Runtime库的扩展SDK函数,首先针对C Runtime库做了一些初始化的工作,以保证C Runtime库工作正常。然后,调用CreateThread真正创建线程。仅使用Runtime Library时,可以用_BegingThread。


AfxBeginThread:MFC中线程创建的MFC函数,首先创建了相应的CWinThread对象,然后调用CWinThread::CreateThread,   在CWinThread::CreateThread中,完成了对线程对象的初始化工作,然后,调用_beginthreadex(AfxBeginThread相比较更为安全)创建线程。它简化了操作或让线程能够响应消息,即可用于界面线程,也可以用于工作者线程。


CreateThread是由操作系统提供的接口,而AfxBeginThread和_BeginThread则是编译器对它的封装。在可能的情况下,不要调用_beginthread,而应该调用_beginthreadex。以及对应的 _endthreadex。这都是C++运行期函数。但是使用_beginthread,无法创建带有安全属性的新线程,无法创建暂停的线程,也无法获得线程ID,_endthread的情况类似,它不带参数




1、MFC程序中使用_beginthreadex()或CreateThread()时要慎重。
AfxBeginThread是MFC的全局函数,是对CreateThread的封装,最终也是调用了CreateThread。AfxBeginThread()是MFC封装的线程启动函数,里面包含了很多和MFC相关的启动信息,而且封装了一些常用的操作,使用起来也比较简便。而用另外两个函数就需要程序员对类型,安全性检查进行更多的思考!


2、用_beginthreadex()函数应该是最佳选择
因为_beginthreadex()函数是C Run-time Library 中的函数,函数的参数和数据类型都是C Run-time Library中的类型,这样在启动线程时就不需要进行Windows数据类型和C Run-time Library中的数据类型之间的转化。降低了线程启动时的资源消耗和时间的消耗!


_beginthreadex:MS对C Runtime库的扩展SDK函数,如果在代码中有使用标准C运行库中的函数时,尽量使用_beginthreadex()来代替CreateThread()。我们只要知道一个问题:_beginthreadex是一个C运行时库的函数,CreateThread是一个系统API函 数,_beginthreadex内部调用了CreateThread。
之所以所有的书都强调内存泄漏的问题是因为_beginthreadex函数在创 建线程的时候分配了一个堆结构并和线程本身关联起来,我们把这个结构叫做tiddata结构,是通过线程本地存储器TLS于线程本身关联起来。我们传入的 线程入口函数就保存在这个结构中。tiddata的作用除了保存线程函数入口地址之外,还有一个重要的作用就是:C运行时库中有些函数需要通过这个结构来 保存和获取一些数据,比如说errno之类的线程全局变量。这点才是最重要的。


3、在C++程序中,几乎都要用到new和delete,难道只有使用_beginthreadex()?(下面有讲到)
不,因为MFC也是C++类库(只不过是Microsoft的C++类库,不是标准的C++类库),在MFC中也封装了new和delete两中运算符,所以用到new和delete的地方不一定非要使用_beginthreadex() 函数,用其他两个函数都可以!
其实在程序中使用上面的哪个函数并不是绝对的,在MFC程序中也可以使用_beginthreadex()和CreateThread()这两个函数,运行的效果也没有多大的区别,有的时候只是需要你额外的进行一些类型检查和其他的一些转化操作,其余没有其他不妥!


当一个线程调用一个需要用到tiddata结构的运行时库函数的时候,将发生下面的情况:运行时库函数试图TlsGetvalue获取线程数据块的地址,如果没有获取到,函数就会现场分配一个 tiddata结构,并且和线程相关联,这时产生了一个问题,如果不通过_endthreadex()函数来终结线程的话,这个结构将不会被撤销,内存泄漏由此产生。但通常情况下,我们都不推荐使用_endthreadex函数来结束线程,因为里面包含了ExitThread调用。


 
找到了内存泄漏的具体原因,我们可以这样说:只要在创建的线程里面不使用一些需要tiddata结构的运行时库函数,我们的内存是安全的。所以,“在你的线程中含有使用需要tiddata结构的C运行时库函数时,绝对不要调用系统自带的CreateThread()函数创建新的线程,而应该使用_beginthreadex()”。


这个需要tiddata结构的函数有点麻烦了,在侯捷的《win32多线程程序设计》一书中这样说到:


”如果在除主线程之外的任何线程中进行以下操作,你就应该使用多线程版本的C runtime library,并使用_beginthreadex和_endthreadex:


1 使用malloc()和free(),或是new和delete


2 使用stdio.h或io.h里面声明的任何函数


3 使用浮点变量或浮点运算函数


4 调用任何一个使用了静态缓冲区的runtime函数,比如:asctime(),strtok()或rand()。”




</线程的创建>


<线程的销毁>


terminatethread


vc中调用TerminateThread终止线程所导致的死锁问题


程序中调用TerminateThread强制终止子线程,结果导致程序死锁。


子线程和主线程都使用了一个临界区变量。主线程创建子线程时,会调用临界区,从而对临界区加锁。子线程运行过程中也会对临界区加锁。这原本是不会导致任何问题的。


为了便于管理临界区,我定义了一个自动锁的类。CAutoLock自动锁,调用构造函数时,加锁,调用析构函数时,解锁。子线程中,就定义了自动锁的对象。——这个自动锁的对象,使用的是栈。


当子线程退出时,应该是解锁了!  即使子线程异常终止,只要栈内存被回收,那么也可以解锁的!因为,回收栈的时候,会调用自动锁对象的析构函数!


这么处理,一直都没有问题。但是,这次却出现了死锁!(和以往不同的是,这次开启了1900多个子线程http://blog.csdn.net/shanzhizi。)


调试结果显示,临界区处于锁定状态,没有解锁!而锁的拥有者是一个已经终止的线程!


由此得出结论:TerminateThread终止线程后,堆栈没有被回收!


当我推出这样的结论时,很快就想到了MSDN上面的说明。以前看到MSDN关于TerminateThread函数的说明,其中提到,TerminateThread结束线程时,不会回收线程的栈!


对于MSDN中的这句话,我一直当它不存在。因为以往的分析结果,TerminateThread结束线程后,栈资源似乎被回收了,栈变量的析构函数被调用了!如果是这样的话,TerminateThread基本上是安全的!至少,对于线程函数局部变量的声明和回收,是安全的!而new的内存,自然还是需要手动回收的了。


但是,这次得出的结论,证明MSDN所说属实!


看来,应该尽量不使用TerminateThread终止线程http://blog.csdn.net/shanzhizi。


MSDN 2005 原文:TerminateThread is used to cause a thread to exit. When this occurs, the target thread has no chance to execute any user-mode code and its initial stack is not deallocated. DLLs attached to the thread are not notified that the thread is terminating.http://blog.csdn.net/shanzhizi


来自:http://zhanyonhu.blog.163.com/blog/static/1618604420103171235276/?fromdm&fromSearch&isFromSearchEngine=yes


</线程的销毁>




  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值