线程的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()的差别的更多相关文章

  1. CloseHandle(),TerminateThread(),ExitThread()的区别

    线程的handle用处:线程的handle是指向“线程的内核对象”的,而不是指向线程本身.每个内核对象只是内核分配的一个内存块,并且只能由内核访问.该内存块是一种数据结构,它的成员负责维护对象的各种信 ...

  2. C++windows内核编程笔记day13 进程、线程与信号量

    Windows进程 进程是一个容器,包括程序运行须要的代码.数据.资源等信息, windows进程的特点: 每一个进程都有自己的ID号 每一个进程都有自己的地址空间.进程之间无法訪问对方的地址空间. ...

  3. 转:Delphi中使用比较少的一些语法

    http://www.cnblogs.com/Murphieston/p/5577836.html 本文是为了加强记忆而写,这里写的大多数内容都是在编程的日常工作中使用频率不高的东西,但是又十分重要. ...

  4. [16]Windows内核情景分析 --- 服务管理

    随时可以看到任务管理器中有一个services.exe进程,这个就是系统的服务控制管理进程,简称SCM 这个进程专门用来管理服务(启动.停止.删除.配置等操作) 系统中所有注册的服务都登记在\HKEY ...

  5. CloseHandle()函数的使用

    CloseHandle()函数的使用?? 很多程序在创建线程都这样写的:............ThreadHandle = CreateThread(NULL,0,.....);CloseHande ...

  6. CWinThread类,使用后要不要使用CloseHandle释放内核

    在VC++中用AfxBeginThread()开启线程的时候,返回的是CWinThead类的指针.但是使用后是否应该用CloseHandle释放内核资源呢? 在<Windows核心编程>中 ...

  7. 线程创建后为什么要调用CloseHandle

    很多程序在创建线程都这样写的: ............ ThreadHandle = CreateThread(NULL,0,.....); CloseHandel(ThreadHandle );  ...

  8. ROLAP和MOLAP的概念和差别

    ROLAP和MOLAP的概念和差别OLAP(on-Line Analysis Processing)是使分析人员.管理人员或执行人员能够从多角度对信息进行快速.一致.交互地存取,从而获得对数据的更深入 ...

  9. apt-get upgarde和dist-upgrade的差别

    apt-get upgarde和dist-upgrade的差别 apt-get upgarde和dist-upgrade的差别   Debian/Ubuntu Linux都使用apt,升级时都是:  ...

随机推荐

  1. JFinal教程1——小白的第一个JFinal程序

    为了使小白能够完全的按步骤创建第一个JFinal应用并运行,笔者将以Java界最流行的Eclipse平台为例,搭建出所有基础教程中喜欢的Hello world应用. 1. JFinal简介 2. 小白 ...

  2. python中eval, exec, execfile,和compile [转载]

    eval(str [,globals [,locals ]])函数将字符串str当成有效Python表达式来求值,并返回计算结果. 同样地, exec语句将字符串str当成有效Python代码来执行. ...

  3. UVALive 6931 Can't stop playing (Regionals 2014 >> Europe - Central)

    题目 一开始有一个双头队列,每次添加一个数(这是数是二的幂,所有数的和不大于\(2^13\)),由你来决定添加到队头还是队尾.如果队列里面相邻的两个数相同,设它们都是\(x\),那么这两个数会合并为\ ...

  4. SQL之概念

    SQL即结构化查询语言,是一个功能强大的数据库语言,可以分为: 1.DML即数据操作语言,用于检索或者修改数据: 2.DDL即数据定义语言,用于定义数据的结构,如创建.修改.删除等: 3.DCL即数据 ...

  5. [置顶] Android中使用sqlite3操作SQLite

    SQLite库包含一个名字叫做sqlite3的命令行,它可以让用户手工输入并执行面向SQLite数据库的SQL命令.本文档提供一个样使用sqlite3的简要说明. 一.创建数据库:  1.将sqlit ...

  6. ORACLE FLASHBACK DATABASE 知识整理

    1.知识储备 1)    只有SYSDBA有权执行,闪回前一定要记录当前SCN 2)    需要停机,并要求处于ARCHIVELOG模式中 3)    闪回日志不能被复用和归档,是自动管理的.RVWR ...

  7. container_of用法及实现

    container_of 有的情况下,只知道 struct结构中莫个成员的指针,而需要知道整个struct的指针 (如网卡驱动里面,list) struct DDD {         int a; ...

  8. windows azure 实例

    public class Album : TableServiceEntity { } public class PhotoAlbumDataContext : TableServiceContext ...

  9. 为进度条增加“伪进度条”?(使用QEventLoop和QTimer)

    在实际开发中,可能会遇到这样的场景:“一个操作非常耗时,但却无法获取其进度百分比”.造成这种情况的原因可能有: 1)该操作属于第三方库(泛指我们使用但无法修改的第三方代码,因此质量有高有底),可能由于 ...

  10. hihocoder1302 最长回文子串

    hihocoder1302 最长回文子串 先贴代码 所有的上面的提示已经交代的好清楚了…… #include <iostream> #include <cstring> #in ...