Win32多线程之核心对象

  CreateThread()传回两个值,用以识别一个新的线程。第一个值是个Handle,  这也是CreateThread()的返回值,大部分与线程有关的API函数都需要它。第二个值是由lpThreadId带回来的线程ID。线程ID是一个全局变量,可以独一无二地表示系统中任一进程中的某个线程。AttachThreadInput()和PostThreadMessage()就需要用到线程ID,这两个函数允许你影响其他人(线程)的消息队列。调试器和进程观察器也需要  线程ID,为了安全防护的缘故,你不可能根据线程的ID而获得其handle。
  CreateThread()传回来的handle被称为一个核心对象(kernal Object)。核心对象其实和所谓的GDI对象,如画笔,画刷或DC是差不多的,只不过它由Kernel.dll来管理,而画笔,画刷由GDI32.dll来管理。两种对象之间有许多相似性。
  GDI对象是Windows的基础部分。在Win16或Win32中它们都是由操作系统管理。通常你不需要知道其数据格式。例如,你可能会调用SelectObject()或ReleaseObject()以处理GDI对象:Windows隐藏了实现细节,只是给你一个HDC或者一个HBRUSH,那都是对象的handle。
  核心对象以HANDLE为使用时的参考依据,与GDI的HBRUSH,HPEN,HPALETTE以及其他handles不同的是,只有一种handle可以代表核心对象。所谓handle,其实是个指针,指向操作系统内存空间的某样东西,那东西不允许你直接取得。你的程序不能够直接取用它,为的是维护系统的完整性与安全性。

   下面是各种Win32核心对象的清单。

  1)进程(processes)

  2)线程(threads)

  3)  文件(files)

  4)事件(events)

  5)信号量(semaphores)

  6)互斥器(mutexes)

  7)管道(Pipes,分为named和anonymous两种)

  其中事件,信号量,互斥器,这些核心对象可以用来整合许多的线程或进程。

  注意:Critical Sections(临界区域、关键区域)并不是核心对象。

  GDI对象和核心对象之间有一个主要的不同,GDI对象有单一拥有者,不是进程就是线程。核心对象可以有一个以上的拥有者,甚至可以跨进程。为了保持对每一位拥有者的追踪,核心对象保持了一个引用计数器,以记录有多少handles对应次对象,对象中也记录了那一个进程或线程是拥有者。如果你调用CreateThread()或是其它会传回handle的函数,引用计数便累加1.当你调用CloseHandle()时,引用计数便递减1.一旦引用计数降至0,这一核心对象即自动被摧毁。

  面对一个打开的对象,区分其拥有者是进程或者是线程。是件很重要的事情。因为这回=会决定系统何时做清除善后(clean up)操作。所谓
clean up操作,包括将该进程或线程所拥有的每一个对象的引用计数减1,若有必要,则对象会被摧毁掉。程序员不能选择由进程或者线程拥有对象,一切得视对象类型而定。
由于引用计数的设计,对象有可能在产生该对象之进程结束之后还继续幸存。Win32提供各种机制,让其他进程得以取得一个核心对象的handle。如果某个进程握有某个核心对象的handle,而该对象的原创者(进程)已经“作古”了,次核心对象并不会被摧毁。
  CloseHandle()的重要性

       当你完成你的工作后,应该调用CloseHandle释放核心对象。

    BOOL  CloseHandle(HANDLE hObject);

    参数
    hObject          代表一个已打开之对象handle
    返回值

     如果成功,CloseHandle()返回TRUE,如果失败则传回FALSE.此时你可以调用GetLastError()获知失败原因。

        如果一个进程没有在结束之前对它所打开的核心对象调用CloseHandle(),操作系统会自动把哪些对象的引用计数下降1.虽然你可以依赖系统做实体(physical)上的清除(cleanup)工作,然而逻辑上的清楚工作又是完全不同的一回事,特别是如果你有多个进程的话,因为系统并不知道对象实际代表什么意义,
所以它不可能知道解构顺序是否重要。
       如果一个进程常常产生“worker 线程”而老是不关闭线程的handle,那么这个进程可能最终有数百甚至数千个开启的“线程核心对象”留给操作系统去清理,这样的资源泄漏可能会对效率带来负面的影响。
      你不可以依赖“因线程的结束而清理所有被这一线程产生的核心对象”。虚度对象,例如文件,是被进程所拥有,而非被线程拥有。在进程结束之前不能够清理它们。

原文地址:https://www.cnblogs.com/rainbow70626/p/8094178.html