Windows 线程的终止

最近参加面试,被面试官问到了Windows线程开发相关的问题,完全回答不上来。百度一下很多关于多线程的说明,在此我整理下便于自己以后查找。

主要问题有

1. 线程的创建

2.线程的销毁

3.线程同步,通信

 

第二节 线程的退出

线程退出方式

1.线程函数返回

2.线程通过调用ExitThread终止自己(自己调用)

3.TerminateThread(本进程或其它进程的线程调用)

4.包含线程的进程终止

第一种是最完美的退出方式,应尽可能使用第一种方法以避免资源泄漏!

 转载https://blog.csdn.net/yangshuangtao/article/details/51284140

线程资源释放
必须明白,一个线程终止和线程资源释放那个不是一个概念。当一个线程以上面几种退出方式终止之后,线程对象及资源还存在于内存中,所以在线程终止之后还需要某种方式释放资源。
 
线程的释放方式与创建方式相关联:
CreateThread创建的线程应使用CloseHandle关闭。
_beginthread创建的线程应使用_endthread关闭。
_beginthreadex创建的线程应使用_endthreadex关闭。
AfxBeginThread创建的线程,如果是线程自己结束自己的线程(从CWinThread继承出来的)就用AfxEndThread。如果外部调用的话可以用PostThreadMessage(m_nThreadID, WM_QUIT,0,0);给这个线程发送消息,线程就会结束的,其中的m_nThreadID是线程ID。

CloseHandle()的方法并不会结束线程,只是释放了handle,线程会继续执行。

_endthread()和_beginthreadx()是在创建的线程内调用,正常线程return时,会自动调用此函数,不用显示调用。如果狭隘线程内显示调用,可能会导致线程内的局部变量没有被释放。 参考https://www.xuebuyuan.com/349166.html


 
线程资源的释放方法(常用):
1、如果对创建线程的引用不感兴趣,可在创建之后直接关闭句柄
void main()
{
    ……
    HANDLE hThread = CreateThread(NULL,0,ThreadFunc,NULL,0,NULL);
    CloseHandle(hThread);
    ……
}
有些新手可能会有个疑问,为什么在刚创建完线程之后就把句柄关掉了?
要特别注意句柄和实例区别,句柄只是对实例对象的引用,用以操作对象。我们使用CreateThread创建了一个线程实例(可将线程整体看作一个对象),返回的线程句柄只是提供了一个方法(类似于指针)让我们可以访问或操作线程对象。我们这里只需要让创建的线程执行必要的代码段就好了,之后并不需要在对其进行任何操作,所以可以直接将其CloseHandle掉,关闭句柄只是切断了访问线程的方式罢了,线程还是存在并运行着的。
然而,只是这样解释还是有所偏差,因为在很多使用CloseHandle关闭其他对象句柄的操作中都会释放对象占用的资源,而对于线程,在调用CloseHandle之后并不会终止线程,也就不会立马释放线程资源(实现中线程还必须继续运行),调用CloseHandle之后系统会递减线程内核对象的使用计数,当线程执行完毕(线程函数执行完)之后也会递减此线程内核对象使用计数,当计数为0时才会释放线程资源!
反过来看,如果不使用CloseHandle关闭线程句柄,那么系统就会一直保持着对此线程内核对象的引用,这样,即使线程执行完毕,使用计数也不会为0,所以线程资源不会被释放。
因此,CloseHandle关闭线程句柄是释放线程资源的必要途径,但不会影响线程的正常运行!所以CloseHandle的调用位置非常灵活,即可在线程刚创建出来之后紧接着调用,也可以在线程执行完之后才调用!
 
2、外部线程WaitForSingleObject,发现线程中止运行后,释放线程相关的资源
void main()
{
     CThread thread; //一个自己定义的线程封装类,其中有一些成员变量,Start启动线程函数,Release释放资源函数。
     thread.Start();
     while(WaitForSingleObject(thread.m_hThread,1000) != WAIT_OBJECT_0)
    {
         //TerminateThread(thread.m_hThread);//在这里如果你不想再等待,可以中止它
         Sleep(1000);
     }
     thread.Release();
}
这种方式的优点是对线程的全面的管理。
缺陷在于,如果要即时释放资源,必须有一个专门的外部的线程来不断的监视或管理线程运行状态。
 
3、线程退出时将自身资源释放
DWORD CALLBACK CThread::Thread(VOID *pParam) //线程的入口函数,static函数
{
     CThread *pthread = pParam;
     ... //工作状态设置
     pthread->Execute()
     ... //工作状态设置
     pthread->Release() //在所有的工作做完之后进行释放资源
     return 0;
}
这种方式的优点是对线程的资源的时机是最准确的,缺陷是必须要保证线程在需要退出时不会阻塞。

 


深入讨论几种创建线程的方式
 
(1)使用_beginthreadex创建的线程就不该用CloseHandle释放,因为,当用_beginThread来创建,而用CloseHandle来关闭线程时,这时复制的全局结构就不会被释放了,这就有了内存的泄漏。这就是很多资料所说的内存泄漏问题的真正的原因。
 
(2)不要在一个MFC程序中使用_beginthreadex()或CreateThread()。这句话的意思是由于AfxBeginThread()是MFC封装的启动线程的函数,里面包含了很多和MFC相关的启动信息,而且封装了一些常用的操作,使用起来也比较简便。而用另外两个函数就需要程序员对类型,安全性检查进行更多的思考!
 
(3)用_beginthreadex()函数应该是最佳选择,因为_beginthreadex()函数是CRun-timeLibrary中的函数,函数的参数和数据类型都是CRun-timeLibrary中的类型,这样在启动线程时就不需要进行Windows数据类型和CRun-timeLibrary中的数据类型之间的转化。减低了线程启动时的资源消耗和时间的消耗!
 
(4)在C程序中,几乎都要用到new和delete,难道只有使用_beginthreadex()?不,因为MFC也是C类库(只不过是Microsoft的C类库,不是标准的C类库),在MFC中也封装了new和delete两中运算符,所以用到new和delete的地方不一定非要使用_beginthreadex()函数,用其他两个函数都可以!其实在程序中使用上面的哪个函数并不是绝对的,书的作者只不过是提了一个更佳的搭配方法,我在MFC程序中也经常使用_beginthreadex()和CreateThread()这两个函数,运行的效果也没有多大的区别,有的时候只是需要你额外的进行一些类型检查和其他的一些转化操作,其余没有其他不妥! 创建线程只有一个方法是::CreateThread()。_beginthreadex()、AfxBeginThread()等内部都是调用这个函数的,因为操作系统只提供这一个接口C静态库比WINDOWS出来还早,就别提多线程了,所以他对多线程的支持不是很好,但后悔也来不急,但也不能怪人家。
 
(5)C运行库_beginthreadex()。他经过一些处理后,再调用CreateThread()如果要强制结束的话也最好用_endthreadex结束,因为他也要一些处理。 总结上面的内容,当然《Windows核心编程》上面得说法是比较权威的。所以,在对线程的结构、运行还不是很了解的时候最好还是按照书上的来。这样能够避免一些可能出现的莫名奇妙的错误,也省去的一些其他结构处理的考虑。当你清楚地知道线程的结构与运行机制,以及了解各个函数对CreateThread函数的封装的时候,大概那时候就能够应用自如了
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值