很多多线程程序都是这样写的:
1 2 |
hThread = CreateThread( NULL, 0, FunProc, NULL, 0, NULL); CloseHandle( hThread ); |
就会产生这样的疑问,为什么创建了多线程,然后就关闭了它…
其实我们认真看语句可以发现,我们创建的是线程,关闭的是句柄…
这是两个不一样的概念。
线程是内核对象,是CPU调度的最小单位。
线程句柄是一个内核对象,我们通过句柄来操作线程。
线程的生命周期和线程句柄的生命周期不一样的:
线程的生命周期就是线程函数从开始执行到返回(return),可能会被强制结束。
线程句柄的生命周期是从CreateThread返回到CloseHandle()。
所有的内核对象都是系统资源,用了要还的,也就是说用完后一定要关闭,如果不这么做,你系统的句柄资源很快就用光了。
什么时候会用到线程句柄呢:
如果你CreateThread以后需要对这个线程做一些操作,比如改变优先级,被其他线程等待,强制TermateThread等,就要保存这个句柄,使用完了在CloseHandle。
如果你开了一个线程,而不需要对它进行如何干预,CreateThread后直接CloseHandle就行了。
所以 CloseHandel(ThreadHandle) 操作 只是关闭了一个线程句柄对象,表示我不再使用该句柄,即不对这个句柄对应的线程做任何干预了,并没有结束线程。
《windows核心编程》上说调用CloseHandle(HANDLE)表示创建者放弃对该内核对象的操作,如果该对象的引用对象记数为0就撤消该对象。
CloseHandle 的功能是关闭一个打开的对象句柄,该对象句柄可以是线程句柄,也可以是进程、信号量等其他内核对象的句柄。
ExitThread 的功能是终止一个线程,它所接受的参数是一个线程的退出码。
通过调用 CloseHandle 可以告知系统,已经完成了对某一内核对象的操作,该函数首先检查调用进程的句柄表,来确认进程是否对该句柄所指向的对象有访问权,如果句柄无效则返回FALSE,如果有效,系统将得到该内核对象的数据结构的地址,把结构中的使用计数成员减1,如果计数变为0,则将从内核中释放该内核对象。
如果计数还未到0,就意味着还有其他的进程在使用这个内核对象,那么它就不会被释放。
CreateThread后那个线程的引用计数不是1,调用CloseHandle只是说自己对这个线程没有兴趣了,引用计数减一,但是线程还是正常运行的。
创建新的进程后,记数初始化为1,而函数需要返回进程内核对象的句柄,相当于打开一次新创建的类核对象,记数再加1,所以CreateThread后那个线程的引用计数不是1,而是2。
若在线程执行完之后,没有调用CloseHandle,在进程执行期间,将会造成内核对象的泄露,相当于句柄泄露,但不同于内存泄露,这势必会对系统的效率带来一定程度上的负面影响。但当进程结束退出后,系统会自动清理这些资源。