关于CreadThread()与CloseHandle()

今天看了点关于Windows多线程的东西,摘抄点关于CloseHandle的内容放于此,以便以后参考。

主要是《Windows核心编程》里的两小节:

3.1.1 内核对象的使用计数
            内核对象由内核所拥有,而不是由进程所拥有。换句话说,如果你的进程调用了一个创建内核对象的函数,然后你的进程终止运行,那么内核对象不一定被撤消。在大多数情况下,对象将被撤消,但是如果另一个进程正在使用你的进程创建的内核对象,那么该内核知道,在另一个进程停止使用该对象前不要撤消该对象,必须记住的是,内核对象的存在时间可以比创建该对象的进程长。
            内核知道有多少进程正在使用某个内核对象,因为每个对象包含一个使用计数。使用计数是所有内核对象类型常用的数据成员之一。当一个对象刚刚创建时,它的使用计数被置为1。然后,当另一个进程访问一个现有的内核对象时,使用计数就递增1。当进程终止运行时,内核就自动确定该进程仍然打开的所有内核对象的使用计数。如果内核对象的使用计数降为0,内核就撤消该对象。这样可以确保在没有进程引用该对象时系统中不保留任何内核对象。
3.2.2 关闭内核对象
            无论怎样创建内核对象,都要向系统指明将通过调用C l o s e H a n d l e来结束对该对象的操作:该函数首先检查调用进程的句柄表,以确保传递给它的索引(句柄)用于标识一个进程实际上无权访问的对象。如果该索引是有效的,那么系统就可以获得内核对象的数据结构的地址,并可确定该结构中的使用计数的数据成员。如果使用计数是0,该内核便从内存中撤消该内核对象。如果将一个无效句柄传递给C l o s e H a n d l e,将会出现两种情况之一。如果进程运行正常,C l o s e H a n d l e返回FA L S E,而G e t L a s t E r r o r则返回E R R O R _ I N VA L I D _ H A N D L E。如果进程正在排除错误,系统将通知调试程序,以便能排除它的错误。
       在C l o s e H a n d l e返回之前,它会清除进程的句柄表中的项目,该句柄现在对你的进程已经无效,不应该试图使用它。无论内核对象是否已经撤消,都会发生清除操作。当调用C l o s e H a n d l e函数之后,将不再拥有对内核对象的访问权,不过,如果该对象的使用计数没有递减为0,那么该对象尚未被撤消。这没有问题,它只是意味着一个或多个其他进程正在使用该对象。当其他进程停止使用该对时(通过调用C l o s e H a n d l e),该对象将被撤消。
            假如忘记调用C l o s e H a n d l e函数,那么会不会出现内存泄漏呢?答案是可能的,但是也不一定。在进程运行时,进程有可能泄漏资源(如内核对象)。但是,当进程终止运行时,操作系统能够确保该进程使用的任何资源或全部资源均被释放,这是有保证的。对于内核对象来说,系统将执行下列操作:当进程终止运行时,系统会自动扫描进程的句柄表。如果该表拥有任何无效项目(即在终止进程运行前没有关闭的对象),系统将关闭这些对象句柄。如果这些对象中的任何对象的使用计数降为0,那么内核便撤消该对象。
            因此,应用程序在运行时有可能泄漏内核对象,但是当进程终止运行时,系统将能确保所有内容均被正确地清除。另外,这个情况适用于所有对象、资源和内存块,也就是说,当进程终止运行时,系统将保证进程不会留下任何对象。

以下是网友的评论:

CreateThread启动了一个线程,同时产生一个句柄让你好操纵这个线程,如果你不要用这个句柄了就CloseHandle关掉它。
调用这个CloseHandle并不意味着结束线程,而是表示不关心此句柄的状态了,也就无法控制子进程的线程了。如果需要关心,可以在子进程结束后再CloseHandle,但一定得CloseHandle。
操作系统内核管理内核对象的生命期,应用程序通过CloseHandle操作内核对象的引用计数,当引用计数由1降为0时,内核负责销毁相应的内核对象。进程和线程都有一个内核对象与它们对应,操作系统通过内核对象管理进程和线程。

本人总结:

当你在程序中,不需要再操作创建的线程时,就CloseHandle掉,即便是那个线程目前计数为1,等你调用CloseHandle后该计数降为0,但已经创建的线程并没有被马上撤消,而是等线程函数执行完毕后才撤消,或者是在线程函数执行完毕前整个进程结束,那么该线程也被撤消。至于为什么在计数降为0时,没有马上撤消该线程,不是很清楚。

 

今天(2007-08-28)又看了下《Windows核心编程》,有了些新的认识:

6.4:当CreateThread被调用时,系统创建一个线程内核对象。该线程内核对象不是线程本身,而是操作系统用来管理线程的较小的数据结构。………………这与进程和进程内核对象之间的关系是相同的。6.6:调用CreateThread可使系统创建一个线程内核对象。该对象的初始使用计数是2(在线程停止运行和从CreateThread返回的句柄关闭之前,线程内核对象不会被撤销)。

根据最后一条就可以解释我昨天的疑问了^_^

 

 

——————————————————————————————————————————————

一,在程序中建立线程的概念

      对于一个进程而言,在进程建立后,同时系统也会为进程自动分配一个主线程。拿Main函数而言,当Main函数执行完后,此时主线程就退出了,主线程退出也同时意味着进程结束。

二,线程、内核对象、内核对象引用计数

      1.创建一个线程有几种方法,这里我们先学习的是利用CreateThread()函数创建线程,此函数的参数及具体用法参见MSDN。如果创建线程成功,函数则返回一个新的线程句柄。(根据《Windows核心编程》,线程创建时,系统设置线程内核对象的引用计数为1,在Create函数返回前,将会打开线程句柄,所以线程的内核对象引用计数+1)

=================================================================================

CreateThread后那个线程的引用计数不是1,而是2。  
   
  creating   a   new   process   causes   the   system   to   create   a   process   kernel   object    
  and   a   thread   kernel   object.   At   creation   time,   the   system   gives   each   object    
  an   initial   usage   count   of   1.   Then,   just   before   CreateProcess   returns,   the    
  function   opens   the   process   object   and   the   thread   object   and   places   the    
  process-relative   handles   for   each   in   the   hProcess   and   hThread   members   of    
  the   PROCESS_INFORMATION   structure.   When   CreateProcess   opens   these   objects    
  internally,   the   usage   count   for   each   becomes   2.                                                  ---摘自《Windows核心编程》

=================================================================================

三,CloseHandle()用法

      1.CloseHandel(ThreadHandle );
只是关闭了一个线程句柄对象,表示我不再使用该句柄,对该句柄不感兴趣,即不对这个句柄对应的线程做任何干预了。并没有结束线程,线程本身还在继续运行。如果你CreateThread以后需要对这个线程做一些操作,比如改变优先级,被其他线程等待,强制TermateThread等,就要保存这个句柄,使用完了再CloseHandle()。

      2.为什么要CreateThread()和CloseHandle()紧挨配套使用

一方面,所有的内核对象(包括线程Handle)都是系统资源,用了要还的,也就是说用完后一定要CloseHandle关闭之,如果不这么做,你系统的句柄资源很快就用光了,另一方面,由于CreateThread()后线程内核对象的引用计数是2,在CloseHandle()引用计数-1之后,内核对象引用计数仍不为0,不会被释放,所以线程仍运行,直到线程函数执行完毕后,引用计数再-1,线程结束。

还可以查看这篇文章  http://hi.baidu.com/heiheijiushiwo/blog/item/02c29924e518e0318644f979.html

启发:

1 windows 核心编程 以后得看

2 系统管理线程是通过线程内部内核对象的引用计数 当此引用计数为0 时线程被关闭

 当在开始 createthread()创建完线程后线程的引用计数为2

调用closehadle()将只关闭不对线程做操作同时将线程引用计数减1

当在线程执行完毕时 引用计数在减1 正常情况下为 0  线程结束

时间: 2024-08-31 14:27:02

关于CreadThread()与CloseHandle()的相关文章

不同WINDOWS平台下磁盘逻辑扇区的直接读写

不同WINDOWS平台下磁盘逻辑扇区的直接读写 关键字:VWIN32.中断.DeviceIoControl 一.概述 在DOS操作系统下,通过BIOS的INT13.DOS的INT25(绝对读).INT26(绝对写)等功能调用实现对磁盘逻辑扇区或物理扇区的读写是很方便的,C语言中还有对应上述功能调用的函数:biosdisk.absread和abswrite等.但在WINDOWS操作系统下编写WIN32应用程序时却再也不能直接使用上述的中断调用或函数了.那么,在WINDOWS操作系统下能不能实现磁盘

核心编程随笔3

Note 1:一个线程可以调用以下两个函数来获取和设置其进程的当前驱动器和目录:DWORD GetCurrentDirectory(DWORD cchCurDir,PTSTR pszCurDir);BOOL SetCurrentDirectory(PCTSTR pszCurDir);注意WinDef.h文件中被定义为260的常量MAX_PATH是目录名称或文件名称的最大字符数.所以在调用GetCurrentDirectory的时候,向该函数传递由MAX_PATH个TCHAR类型的元素构成的一个缓

自己创建的文件夹-mfc对话框批量创建文件夹和空文件

问题描述 mfc对话框批量创建文件夹和空文件 mfc对话框批量创建文件夹和空文件,创建文件夹和文件,才学mfc,求解答,求案例 解决方案 CreateDirectory API 解决方案二: 创建空文件用CreateFile,再 CloseFile 解决方案三: 可以用windowsAPI,可以用System()执行md命令. 解决方案四: 得到sFolder了,就可以CreateFile来创建. 解决方案五: CreateDirectory/CFile::Open(...)/Close()/C

c++-求教!通过内存映射,实现生成的数组存储到文件中,显示出来头100个数?

问题描述 求教!通过内存映射,实现生成的数组存储到文件中,显示出来头100个数? 我目前就了解个大概,现在我不明白const DWORD mmf_size = 512*1024;//?这个地方不懂 ,这个原来的代码部分,我拿别人的代码改的,增加了自己的double的动态数组SigNRead,这个怎么弄 我就想实现,通过内存映射 实现写入 读取 double数组 数组有 1列 90000行个double数组成. #include #include #include #include #define

Detours 拦截API导致目标程序崩溃

问题描述 Detours 拦截API导致目标程序崩溃 系统环境为Windows7,X64,注入程序,DLL,目标程序为VS2013生成的Win32项目 代码再回复中贴出 解决方案 数组越界导致程序崩溃 解决方案二: // dllmain.cpp : Defines the entry point for the DLL application. #include "stdafx.h" #include "detours.h" #include #include #i

vhd 转换为img源码,由VS 2010 C++编译

本工程主要由vhd2img.cpp layout.h组成,C代码实现. vhd2img.cpp: // vhd2img.cpp : 定义控制台应用程序的入口点. //by www.frombyte.cn zhangyu //北亚数据恢复中心(www.sjhf.net)张宇 2012/1/6 发表于51cto #include "stdafx.h" #include <windows.h> #include "layout.h" #define VHD_O

EXE和DLL中FindResource的区别

以下的代码在EXE中,执行无误.可是在DLL中FindResource返回的值就为0了,我用::GetLastError(),得出的值是1813,也就是取不到资源,这是为什么? BOOL ExtractFile(char *szZlibFile,DWORD dwRID) { HANDLE hFile = NULL ; HRSRC hRsrc = NULL ; HGLOBAL hGlobal = NULL ; DWORD dwResSize = 0, dwBytesWrite = 0, dwByt

asp调用vb生成的dll文件,执行shell异步变同步的解决方法(带源代码)

vb|解决|源代码|执行|shell|异步|同步 阿里西西web开发团队在开发一个asp系统,需要同步调用vb(dll)执行的shell操作,asp->vb(dll)->shell->rar.exe同步执行exe文件. 由于shell是异步处理,这个问题让我们头疼了很久,最终还是通过百度找到了几个不错的函数,调试过,效果还不错,建议可以先用vb建exe来调试好了,再放入DLL编译给ASP调用. 代码如下: 以下是用vb制作一个exe文件进行调试,打开记事本和计算器示例:Private T

让Java程序自带JRE

程序   用Java开发程序,发布时总要考虑的问题就是怎么在使用者的机器上装好JRE.要考虑的问题很多:使用者有没有能力独自安装JRE,使用者已有的JRE和我们需要的版本是不是一致,会不会出现版本问题,等等.使用.NET要考虑的问题就少些.现在.NET CLR似乎已经很普及了,看好多D版的Win XP都会自己安装最新的.NET CLR,而且似乎它的安装界面也比JRE友好些.彻底解决安装JRE的问题的方案,就是让我们的应用程序自己背着JRE!这样,我们的程序就像传统的Win32应用程序一样,双击就