CloseHandle(),TerminateThread(),ExitThread()的差别
线程的handle用处:
线程的handle是指向“线程的内核对象”的,而不是指向线程本身.每一个内核对象仅仅是内核分配的一个内存块,而且仅仅能由内核訪问。该内存块是一种数据结构,它的成员负责维护对象的各种信息(eg: 安全性描写叙述,引用计数等)。
CloseHandle()
在CreateThread成功之后会返回一个hThread的handle,且内核对象的计数加1,CloseHandle之后,引用计数减1,当变为0时,系统删除内核对象。
可是这个handle并不能全然代表这个线程,它不过线程的一个“标识”,系统和用户能够利用它对对应的线程进行必要的操纵。假设在线程成功创建后,不再须要用到这个句柄,就能够在创建成功后,线程退出前直接CloseHandle掉,但这并不会影响到线程的执行。
不运行CloseHandle() 带来的后果:
若在线程运行完之后,没有通过CloseHandle()将引用计数减1,在进程运行期间,将会造成内核对象的泄露,相当与句柄泄露,但不同于内存泄露, 这势必会对系统的效率带来一定程度上的负面影响。可是,请记住,当进程结束退出后,系统仍然会自己主动帮你清理这些资源。可是在这里不推荐这样的做法,毕竟不是 一个良好的编程习惯!
( 应用程序执行时,有可能泄露内核对象,可是当进程终止执行时,系统能确保全部内容均被正确地清除。另外,这个情况是用于全部对象,资源和内存块,也就是说,当进程终止时,系统将保证不会留下不论什么对象。)
TerminateThread()
函数的声明例如以下:
BOOL TerminateThread( HANDLE hThread, DWORD dwExitCode);
作用:
在线程外终止一个线程,用于强制终止线程。
參数说明:
HANDLE htread:被终止的线程的句柄,为CWinThread指针。
DWORD dwExitCode:退出码。
返回值:
函数运行成功则返回非零值,运行失败返回0。调用getlasterror获得返回的值。
听过无数次不要TerminateThread,仅仅是工作中经常使用,貌似也没有什么问题。今天在高强度測试中发现了一个不可原谅的错误。參看以下的样例
DWORD __stdcall mythread(void*)
{
while( true )
{
char* p = new char[1024];
delete [] p;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE h = CreateThread(NULL, 0, mythread, NULL, 0, NULL);
Sleep(1000);
TerminateThread(h , 0);
h = NULL;
char* p = new char[1024]; // 这里会死锁, 过不去
delete [] p;
return 0;
}
为什么死锁呢?new操作符用的是小块堆,整个进程在分配和回收内存时,都要用同一把锁。假设一个线程在占用该锁时被杀死(即临死前该线程在new或delete操作中),其它线程就无法再使用new或delete了,表现为hang住。
<核心编程>里明白提醒不要TerminateThread,但原因并非血淋淋滴。今天发现的这个bug印证了此书的价值。
另注:很多暂时的网络操作经经常使用TerminateThread,作为网络不通时的退出机制,以后要改改了。比方让该线程自生自灭,自行退出。
ExitThread是推荐使用的结束一个线程的方法,当调用该函数时,当前线程的栈被释放,然后线程终止,相对于TerminateThread函数来说,这样做可以更好地完毕附加在该线程上的DLL的清除工作
终止线程两个函数:ExitThread() 和 TerminateThread()
若要终止线程的执行,能够使用以下四种的方法:
线程函数退出循环来返回 (最佳方法 )。
通过调用ExitThread 函数,线程将自行撤消(尽量不要使用这样的方法 )。
同一个进程或还有一个进程中的线程调用TerminateThread 函数(最好避免使用这样的方法 )。
该线程的主进程终止执行(避免使用 )。
以下将介绍终止线程执行的方法,而且说明线程终止执行时会出现什么情况。
1.线程函数返回
始终都应该将线程设计成这种形式,即当想要线程终止执行时,它们就行返回。这是
确保全部线程资源被正确地清除的唯一办法。
假设线程可以返回,就行确保下列事项的实现:
a) 在线程函数中创建的全部C + +对象均将通过它们的撤消函数正确地撤消。
b)操作系统将正确地释放线程堆栈使用的内存。
c)系统将线程的退出代码(在线程的内核对象中维护)设置为线程函数的返回值。
d)系统将递减线程内核对象的使用计数。
2.ExitThread 函数
能够让线程调用ExitThread 函数,以便强制线程终止执行:
该函数将终止线程的执行,并导致操作系统清除该线程使用的全部操作系统资源。可是,C++资源(如C++类对象)将不被撤消。因为这个原因,最好从线程函数返回,而不是通过调用ExitThread 来返回。
当然,能够使用ExitThread 的dwExitThread 參数告诉系统将线程的退出代码设置为什么。ExitThread 函数并不返回不论什么值,由于线程已经终止执行,不能执行很多其它的代码。
注意终止线程执行的最佳方法是让它的线程函数返回。可是,假设使用本节介绍的方法,应该知道ExitThread 函数是Windows用来撤消线程的函数。假设编写C/C++代码,那么决不应该调用ExitThread 。应该使用Visual C++执行期库函数_endthreadex。假设不使用Microsoft的Visual C++编译器,你的编译器供应商有它自己的ExitThread 的替代函数。无论这个替代函数是什么,都必须使用。本章后面将说明_endthreadex的作用和它的重要性。
3.TerminateThread 函数
调用TerminateThread 函数也可以终止线程的执行:
与ExitThread 不同,ExitThread 总是撤消调用的线程,而TerminateThread 可以撤消不论什么线程。hThread參数用于标识被终止执行的线程的句柄。当线程终止执行时,它的退出代码成为你作为dwExitThread 參数传递的值。同一时候,线程的内核对象的使用计数也被递减。
注意TerminateThread 函数是异步执行的函数,也就是说,它告诉系统你想要线程终止执行,可是,当函数返回时,不能保证线程被撤消。假设须要确切地知道该线程已经终止执行,必须调用WaitForSingleObject或者类似的函数,传递线程的句柄。
设计良好的应用程序从来不使用这个函数,由于被终止执行的线程收不到它被撤消的通知。线程不能正确地清除,而且不能防止自己被撤消。注意当使用返回或调用ExitThread 的方法撤消线程时,该线程的内存堆栈也被撤消。可是,假设使用TerminateThread ,那么在拥有线程的进程终止执行之前,系统不撤消该线程的堆栈。Microsoft有益用这样的方法来实现TerminateThread 。假设其它仍然正在执行的线程要引用强制撤消的线程堆栈上的值,那么其它的线程就会出现訪问违规的问题。假设将已经撤消的线程的堆栈留在内存中,那么其它线程就能够继续非常好地执行。此外,当线程终止执行时,
DLL通常接收通知。假设使用Terminate Thread 强迫线程终止,DLL就不接收通知,这能阻止适当的清除(具体信息參见第20章)。
4.在进程终止执行时撤消线程
ExitProcess和TerminateProcess函数也能够用来终止线程的执行。区别在于这些线程将会使终止执行的进程中的全部线程全部终止执行。另外,因为整个进程已经被关闭,进程使用的全部资源肯定已被清除。这当然包含全部线程的堆栈。这两个函数会导致进程中的剩余线程被强制撤消,就像从每一个剩余的线程调用TerminateThread 一样。显然,这意味着正确的应用程序清除没有发生,即C++对象撤消函数没有被调用,数据没有转至磁盘等等。
CloseHandle(),TerminateThread(),ExitThread()的差别的更多相关文章
- CloseHandle(),TerminateThread(),ExitThread()的区别
线程的handle用处:线程的handle是指向“线程的内核对象”的,而不是指向线程本身.每个内核对象只是内核分配的一个内存块,并且只能由内核访问.该内存块是一种数据结构,它的成员负责维护对象的各种信 ...
- C++windows内核编程笔记day13 进程、线程与信号量
Windows进程 进程是一个容器,包括程序运行须要的代码.数据.资源等信息, windows进程的特点: 每一个进程都有自己的ID号 每一个进程都有自己的地址空间.进程之间无法訪问对方的地址空间. ...
- 转:Delphi中使用比较少的一些语法
http://www.cnblogs.com/Murphieston/p/5577836.html 本文是为了加强记忆而写,这里写的大多数内容都是在编程的日常工作中使用频率不高的东西,但是又十分重要. ...
- [16]Windows内核情景分析 --- 服务管理
随时可以看到任务管理器中有一个services.exe进程,这个就是系统的服务控制管理进程,简称SCM 这个进程专门用来管理服务(启动.停止.删除.配置等操作) 系统中所有注册的服务都登记在\HKEY ...
- CloseHandle()函数的使用
CloseHandle()函数的使用?? 很多程序在创建线程都这样写的:............ThreadHandle = CreateThread(NULL,0,.....);CloseHande ...
- CWinThread类,使用后要不要使用CloseHandle释放内核
在VC++中用AfxBeginThread()开启线程的时候,返回的是CWinThead类的指针.但是使用后是否应该用CloseHandle释放内核资源呢? 在<Windows核心编程>中 ...
- 线程创建后为什么要调用CloseHandle
很多程序在创建线程都这样写的: ............ ThreadHandle = CreateThread(NULL,0,.....); CloseHandel(ThreadHandle ); ...
- ROLAP和MOLAP的概念和差别
ROLAP和MOLAP的概念和差别OLAP(on-Line Analysis Processing)是使分析人员.管理人员或执行人员能够从多角度对信息进行快速.一致.交互地存取,从而获得对数据的更深入 ...
- apt-get upgarde和dist-upgrade的差别
apt-get upgarde和dist-upgrade的差别 apt-get upgarde和dist-upgrade的差别 Debian/Ubuntu Linux都使用apt,升级时都是: ...
随机推荐
- 查询某库所有表的rows &查看当前sql的注册信息
查询某库所有表的rows &查看当前sql的注册信息 1 2 3 4 5 6 7 select sobj.name,spar.rows FROM sys.objects sobj INNER ...
- 一天一个类,一点也不累之HashSet
最近忙着一个小项目结题,故没能按时完成[一天一个类,一点也不累],还好项目优秀,算是对自己一点点的安慰和鼓励.~~~ 今天要说的是HashSet 既然是继承自Set,那么就必须有Set的一些属性,比如 ...
- java--内部类实现“类的多重继承”
class Fa1{ private int k = 1; void show() { System.out.println(k); } } class Fa2{ private int k = 10 ...
- Windows Phone 8初学者开发—第22部分:用演示图板创建卷盘的动画
原文 Windows Phone 8初学者开发—第22部分:用演示图板创建卷盘的动画 第22部分: 用演示图板创建卷盘的动画 原文地址:http://channel9.msdn.com/Series/ ...
- solr 从零学习开始
2010-10 目 录 1 1.1 1.2 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.3 1.3.1 1.3.2 1.4 1.4.1 1.4.2 1.4. ...
- MFC 之 截图工具
这个截图工具能实现最主要的截图功能,并保存为bmp图片. 编写环境是vs2005,使用Unicode,基于对话框. 没什么难度,直接看代码 项目名称为CutOut // CutOutDlg.h : 头 ...
- 【Unity 3D】使用 2DToolkit 插件 制作2D精灵动画
话说博客传图也太麻烦了吧,一个一个文件一个一个传....为什么不能直接粘贴了,自动上传呢... 刚直接粘贴了,结果一张图没有,又重新截一次图,在传了一次...真是太**了 好了,吐槽完了,开始博客吧 ...
- 搭建python集成开发环境.
需要搭建的内容一共有三项, python ,wxpython 以及spe. 其中spe 是python 的可视化集成开发环境(ide) , 其需要python GUI图形库wxpython的支 ...
- Linux的五个查找命令 [转]
最近,我在学习Linux,下面是一些笔记. 使用电脑的时候,经常需要查找文件. 在Linux中,有很多方法可以做到这一点.国外网站LinuxHaxor总结了五条命令,你可以看看自己知道几条.大多数程序 ...
- java.lang.ClassNotFoundException与java.lang.NoClassDefFoundError的区别(转)
ClassNotFoundException ClassNotFoundException这个错误,比较常见也好理解. 原因:就是找不到指定的class. 常见的场景就是: 1 调用class的for ...