windows线程退出的方法

线程的handle用处:编程

线程的handle是指向“线程的内核对象”的,而不是指向线程自己.每一个内核对象只是内核分配的一个内存块,而且只能由内核访问。该内存块是一种数据结构,它的成员负责维护对象的各类信息(eg: 安全性描述,引用计数等)。安全

 

CloseHandle()网络

在CreateThread成功以后会返回一个hThread的handle,且内核对象的计数加1,CloseHandle以后,引用计数减1,当变为0时,系统删除内核对象。数据结构

可是这个handle并不能彻底表明这个线程,它仅仅是线程的一个“标识”,系统和用户能够利用它对相应的线程进行必要的操纵。若是在线程成功建立后,再也不须要用到这个句柄,就能够在建立成功后,线程退出前直接CloseHandle掉,但这并不会影响到线程的运行。异步

 

不执行CloseHandle() 带来的后果:函数

若在线程执行完以后,没有经过CloseHandle()将引用计数减1,在进程执行期间,将会形成内核对象的泄露,至关与句柄泄露,但不一样于内存泄露, 这势必会对系统的效率带来必定程度上的负面影响。可是,请记住,当进程结束退出后,系统仍然会自动帮你清理这些资源。可是在这里不推荐这种作法,毕竟不是 一个良好的编程习惯!
( 应用程序运行时,有可能泄露内核对象,可是当进程终止运行时,系统能确保全部内容均被正确地清除。另外,这个状况是用于全部对象,资源和内存块,也就是说,当进程终止时,系统将保证不会留下任何对象。)
测试

 

TerminateThread()spa

函数的声明以下:操作系统

 
BOOL TerminateThread( HANDLE hThread, DWORD dwExitCode);
 
做用:
 
在线程外终止一个线程,用于强制终止线程。
 
参数说明:
 
HANDLE htread:被终止的线程的句柄,为CWinThread指针。
 
DWORD dwExitCode:退出码。
 
返回值:
 
函数执行成功则返回非零值,执行失败返回0。调用getlasterror得到返回的值。

 

 

听过无数次不要TerminateThread,只是工做中经常使用,貌似也没有什么问题。今天在高强度测试中发现了一个不可原谅的错误。参看下面的例子.net

 

[cpp]  view plain copy
 
  1. DWORD __stdcall mythread(void*)    
  2. {    
  3.     whiletrue )    
  4.     {    
  5.         char* p = new char[1024];    
  6.     
  7.         delete [] p;    
  8.     }    
  9. }    
  10.     
  11. int _tmain(int argc, _TCHAR* argv[])    
  12. {    
  13.     
  14.     HANDLE h = CreateThread(NULL, 0, mythread, NULL, 0, NULL);    
  15.     
  16.     Sleep(1000);    
  17.     
  18.     TerminateThread(h , 0);    
  19.     h = NULL;    
  20.     
  21.     char* p = new char[1024]; // 这里会死锁, 过不去    
  22.     
  23.     delete [] p;    
  24.     
  25.     return 0;    
  26. }  

 

为何死锁呢?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++对象撤消函数没有被调用,数据没有转至磁盘等等。

相关文章
相关标签/搜索