CreateThread和CloseThread

jingank 2011-04-19 10:08:12
谁能讲解一下CloseThraed的用法 什么时候用?为什么?
...全文
712 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
for_onxx 2011-04-27
  • 打赏
  • 举报
回复
HANDLE handle = CreateThread(NULL,0,&ThreadFunc,NULL,NULL);
......//使用handle的代码
CloseHandle(handle);//不再使用handle
Lactoferrin 2011-04-22
  • 打赏
  • 举报
回复
HandleCount=2是因为csrss也有一个句柄,用RtlCreateUserThread创建出来的HandleCount=1,因为RtlCreateThread不会CsrClientCallServer通知csrss
Loren 2011-04-22
  • 打赏
  • 举报
回复
为什么线程创建时计数初值为2??

【1.创建的线程函数本生拥有一个handle引用计数,而且这个引用计数是不能用closehandle去掉的。它只有在线程函数结束时才减1.这也保证了,不会因为用户多次调用closehandle,导致引用计数为0而销毁线程内核对象。
2.当创建线程是,API返回了一个handle,按系统的设计,任何新创建的handle都需要一个closehandle与之对应。因此这里也需要一个引用计数。
3.根据1和2,系统给的初始化引用计数值应该为2,上面的调试也验证这个值】
jingank 2011-04-22
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 lorenzhai 的回复:]

Handle,是一个内核对象在Win32中的一种表示方法,该内核变量同时有个引用计数。
CloseHandle,一般用来对内核变量进行操作,调用一次这个函数,对应内核对象的引用计数就减1。如果计数到零,系统就销毁该内核对象(这个跟COM接口的引用计数很类似)

对于CreateThread,调用后,有两个线程堆栈,一个用户态的,一个内核态的,内核的Ethread,Kthread结构里包含了……
[/Quote]

为什么线程创建时计数初值为2??
Lactoferrin 2011-04-22
  • 打赏
  • 举报
回复
CreateThread会通知csrss.exe,csrss.exe进程也会有一个这个线程的句柄,
PointerCount不会小于HandleCount
Loren 2011-04-22
  • 打赏
  • 举报
回复
历史背景没注意,我也是在调试的时候发现这个问题的。
看下面线程89582a98和89534630的HandleCount,一个为2,一个为1.为1的,是我在createthread后,直接有一个closehandle的动作。

Code:

void ThreadDemo()
{
DWORD dwThreadID(0);
for(int i=0;i<2;i++)
{
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadHandleCountTest, (void*)&i, 0, (UINT*)&dwThreadID);
if( i == 1)
{
CloseHandle(hThread);
}
}
}

unsigned __stdcall ThreadHandleCountTest(LPVOID pData)
{
while(1)
{
Sleep(100);
}

return 0;
}


Debug

0: kd> !process 0 0 ThreadRefCount.exe
PROCESS 898c5698 SessionId: 1 Cid: 1e48 Peb: 7ffd5000 ParentCid: 0d50
DirBase: 7b80dda0 ObjectTable: acc0d6b8 HandleCount: 41.
Image: ThreadRefCount.exe
0: kd> .process /p /r 898c5698
Implicit process is now 898c5698
Loading User Symbols
.................
0: kd> .process 898c5698
Implicit process is now 898c5698
0: kd> !process 898c5698 4
PROCESS 898c5698 SessionId: 1 Cid: 1e48 Peb: 7ffd5000 ParentCid: 0d50
DirBase: 7b80dda0 ObjectTable: acc0d6b8 HandleCount: 41.
Image: ThreadRefCount.exe

THREAD 8bcce580 Cid 1e48.1f90 Teb: 7ffdf000 Win32Thread: fe4b3b78 WAIT
THREAD 89582a98 Cid 1e48.1f28 Teb: 7ffde000 Win32Thread: 00000000 WAIT
THREAD 89534630 Cid 1e48.18a4 Teb: 7ffdd000 Win32Thread: 00000000 WAIT
0: kd> dt _object_header 89582a98-0x18
ntdll!_OBJECT_HEADER
+0x000 PointerCount : 0n3
+0x004 HandleCount : 0n2
+0x004 NextToFree : 0x00000002 Void
+0x008 Type : 0x88c70040 _OBJECT_TYPE
+0x00c NameInfoOffset : 0 ''
+0x00d HandleInfoOffset : 0 ''
+0x00e QuotaInfoOffset : 0x10 ''
+0x00f Flags : 0 ''
+0x010 ObjectCreateInfo : 0x8b724378 _OBJECT_CREATE_INFORMATION
+0x010 QuotaBlockCharged : 0x8b724378 Void
+0x014 SecurityDescriptor : 0xaa51c2f5 Void
+0x018 Body : _QUAD
0: kd> dt _object_header 89534630-0x18
ntdll!_OBJECT_HEADER
+0x000 PointerCount : 0n2
+0x004 HandleCount : 0n1
+0x004 NextToFree : 0x00000001 Void
+0x008 Type : 0x88c70040 _OBJECT_TYPE
+0x00c NameInfoOffset : 0 ''
+0x00d HandleInfoOffset : 0 ''
+0x00e QuotaInfoOffset : 0x10 ''
+0x00f Flags : 0 ''
+0x010 ObjectCreateInfo : 0x8b724378 _OBJECT_CREATE_INFORMATION
+0x010 QuotaBlockCharged : 0x8b724378 Void
+0x014 SecurityDescriptor : 0xaa51c2f5 Void
+0x018 Body : _QUAD
0: kd> !process 898c5698
PROCESS 898c5698 SessionId: 1 Cid: 1e48 Peb: 7ffd5000 ParentCid: 0d50
DirBase: 7b80dda0 ObjectTable: acc0d6b8 HandleCount: 41.
Image: ThreadRefCount.exe
VadRoot 8b0c50d8 Vads 52 Clone 0 Private 241. Modified 7. Locked 0.
DeviceMap 859f8678
Token b5c8ec48
ElapsedTime 00:00:02.530
UserTime 00:00:00.000
KernelTime 00:00:00.000
QuotaPoolUsage[PagedPool] 81136
QuotaPoolUsage[NonPagedPool] 2496
Working Set Sizes (now,min,max) (1580, 50, 345) (6320KB, 200KB, 1380KB)
PeakWorkingSetSize 1580
VirtualSize 44 Mb
PeakVirtualSize 50 Mb
PageFaultCount 1608
MemoryPriority BACKGROUND
BasePriority 8
CommitCharge 475
Job 898e6888

THREAD 8bcce580 Cid 1e48.1f90 Teb: 7ffdf000 Win32Thread: fe4b3b78 WAIT: (WrUserRequest) UserMode Non-Alertable
89890770 SynchronizationEvent
Not impersonating
DeviceMap 859f8678
Owning Process 898c5698 Image: ThreadRefCount.exe
Attached Process N/A Image: N/A
Wait Start TickCount 5083543
Context Switch Count 648
UserTime 00:00:00.000
KernelTime 00:00:00.031
*** WARNING: Unable to verify checksum for ThreadRefCount.exe
Win32 Start Address ThreadRefCount!WinMainCRTStartup (0x004017b0)
Stack Init c8eb4000 Current c8eb3b68 Base c8eb4000 Limit c8eb1000 Call 0
Priority 11 BasePriority 8 PriorityDecrement 1 IoPriority 2 PagePriority 5
ChildEBP RetAddr
c8eb3b80 86eca372 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])
c8eb3bc4 86e65f38 nt!KiSwapThread+0x44f
c8eb3c18 a1f08bbc nt!KeWaitForSingleObject+0x492
c8eb3c74 a1f089f3 win32k!xxxRealSleepThread+0x1ad (FPO: [Non-Fpo])
c8eb3c90 a1f0872e win32k!xxxSleepThread+0x2d (FPO: [Non-Fpo])
c8eb3ce8 a1f09247 win32k!xxxRealInternalGetMessage+0x4a4 (FPO: [Non-Fpo])
c8eb3d4c 86e68c7a win32k!NtUserGetMessage+0x3f (FPO: [Non-Fpo])
c8eb3d4c 77585ca4 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ c8eb3d64)
0012fe30 7673feef ntdll!KiFastSystemCallRet (FPO: [0,0,0])
0012fe34 76738af3 USER32!NtUserGetMessage+0xc (FPO: [4,0,0])
0012fe58 00401ba0 USER32!GetMessageA+0x8a (FPO: [Non-Fpo])
0012fee8 00401963 ThreadRefCount!WinMain+0x100
0012ff88 7686d0e9 ThreadRefCount!WinMainCRTStartup+0x1b3 [crtexe.c @ 330]
0012ff94 775616c3 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
0012ffd4 77561696 ntdll!__RtlUserThreadStart+0x23 (FPO: [Non-Fpo])
0012ffec 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

THREAD 89582a98 Cid 1e48.1f28 Teb: 7ffde000 Win32Thread: 00000000 WAIT: (DelayExecution) UserMode Non-Alertable
89582b20 NotificationTimer
Not impersonating
DeviceMap 859f8678
Owning Process 898c5698 Image: ThreadRefCount.exe
Attached Process N/A Image: N/A
Wait Start TickCount 5086483
Context Switch Count 801
UserTime 00:00:00.000
KernelTime 00:00:00.000
*** ERROR: Symbol file could not be found. Defaulted to export symbols for MSVCRTD.dll -
Win32 Start Address MSVCRTD!beginthreadex (0x1020bf20)
Stack Init 84e48000 Current 84e47c50 Base 84e48000 Limit 84e45000 Call 0
Priority 10 BasePriority 8 PriorityDecrement 2 IoPriority 2 PagePriority 5
ChildEBP RetAddr
84e47c68 86eca372 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])
84e47cac 86ec7a4e nt!KiSwapThread+0x44f
84e47d08 87051eee nt!KeDelayExecutionThread+0x472
84e47d54 86e68c7a nt!NtDelayExecution+0x8d
84e47d54 77585ca4 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 84e47d64)
0189fe7c 775845d0 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
0189fe80 76869990 ntdll!NtDelayExecution+0xc (FPO: [2,0,0])
0189fee8 76821c6c kernel32!SleepEx+0x62 (FPO: [Non-Fpo])
0189fef8 004010e3 kernel32!Sleep+0xf (FPO: [Non-Fpo])
0189ff50 1020bfd2 ThreadRefCount!GetURLWorkThread+0x33
WARNING: Stack unwind information not available. Following frames may be wrong.
0189ff88 7686d0e9 MSVCRTD!beginthreadex+0x172
0189ff94 775616c3 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
0189ffd4 77561696 ntdll!__RtlUserThreadStart+0x23 (FPO: [Non-Fpo])
0189ffec 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

THREAD 89534630 Cid 1e48.18a4 Teb: 7ffdd000 Win32Thread: 00000000 WAIT: (DelayExecution) UserMode Non-Alertable
895346b8 NotificationTimer
Not impersonating
DeviceMap 859f8678
Owning Process 898c5698 Image: ThreadRefCount.exe
Attached Process N/A Image: N/A
Wait Start TickCount 5086484
Context Switch Count 614
UserTime 00:00:00.000
KernelTime 00:00:00.000
Win32 Start Address MSVCRTD!beginthreadex (0x1020bf20)
Stack Init 84fd5000 Current 84fd4c50 Base 84fd5000 Limit 84fd2000 Call 0
Priority 10 BasePriority 8 PriorityDecrement 2 IoPriority 2 PagePriority 5
ChildEBP RetAddr
84fd4c68 86eca372 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])
84fd4cac 86ec7a4e nt!KiSwapThread+0x44f
84fd4d08 87051eee nt!KeDelayExecutionThread+0x472
84fd4d54 86e68c7a nt!NtDelayExecution+0x8d
84fd4d54 77585ca4 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 84fd4d64)
0199fe7c 775845d0 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
0199fe80 76869990 ntdll!NtDelayExecution+0xc (FPO: [2,0,0])
0199fee8 76821c6c kernel32!SleepEx+0x62 (FPO: [Non-Fpo])
0199fef8 004010e3 kernel32!Sleep+0xf (FPO: [Non-Fpo])
0199ff50 1020bfd2 ThreadRefCount!GetURLWorkThread+0x33
WARNING: Stack unwind information not available. Following frames may be wrong.
0199ff88 7686d0e9 MSVCRTD!beginthreadex+0x172
0199ff94 775616c3 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
0199ffd4 77561696 ntdll!__RtlUserThreadStart+0x23 (FPO: [Non-Fpo])
0199ffec 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

yao050421103 2011-04-19
  • 打赏
  • 举报
回复
如果你不是要关闭线程句柄,而是要结束一个线程的话,用ExitThread或者TerminateThread。
其中,ExitThread是在线程内部自行结束;TerminateThread则是由一个线程强制终止另外一个线程。
yao050421103 2011-04-19
  • 打赏
  • 举报
回复
没有CloseThread吧?如果你要关闭线程的话,应该是用CloseHandle()。
一般的用法:
HANDLE hThread = CreateThread(...);
CloseHandle(hThread);
说明:如果你是在主线程创建一个子线程之后立刻CloseHandle,那么之后主线程就不再拥有对该子线程的控制权,也即是你在主线程里面对子线程的任何操作都将无效。
如果CreateThread之后没有CloseHandle,那么你可以在主线程里面控制子线程,比如线程的挂起、恢复等,也可以在主线程里面结束子线程。
Eleven 2011-04-19
  • 打赏
  • 举报
回复
Closing a thread handle does not terminate the associated thread or remove the thread object. Closing a process handle does not terminate the associated process or remove the proces object. To remove a thread object, you must terminate the thread, then close all handles to the thread. For more information, see Terminating a Thread. To remove a process object, you must terminate the process, then close all handles to the process. For more information, see Terminating a Process.

King_hhuang 2011-04-19
  • 打赏
  • 举报
回复
要想控制一个线程的结束,有很多办法

1,

BOOL TerminateThread(
HANDLE hThread,
DWORD dwExitCode
);
这个函数强制结束一个线程。但是不保证数据的释放,这样会带来很大的后遗症。类似的还有
VOID ExitThread(
DWORD dwExitCode
);
还有mfc提供的_endthread();等都是一样的。

2,利用全局变量通知线程结束。
在线程回调里面,判断全局变量是不是变化了,然后结束。
这样外界通知时,就要改变全局变量的值,然后等待线程回调检测到全局变量的变化。
3,利用event事件通知
创建一个event对象m_hTerminate,用来通知线程何时结束;通知后同时waitsingleobject(线程句柄);
而在线程的回调里面则这样写:
while (1)
{
//测试一下是不是关闭信号来了
DWORD dwResult=WaitForSingleObject(pThis->m_hTerminate,0);
if (WAIT_OBJECT_0==dwResult)
{
break;
}
else
{
...
}
return 0;
}
这样如果主线程发出了 SETEVENT(m_hTerminate),回调函数就能立即检测到然后返回。此时主线程要
BOOL CSerialComu::Stop()
{
SetEvent(m_hTerminate);
WaitForSingleObject(m_hTread,INFINITE);
CloseHandle(m_hThread);
return TRUE;
}
这样就能干净利索的结束,并且安静的等待结束了。
King_hhuang 2011-04-19
  • 打赏
  • 举报
回复
只有
TerminateThread
ExitThread
_endthread
就是结束线程
jingank 2011-04-19
  • 打赏
  • 举报
回复
。。。。。是CloseHandle() 见笑。。。。
Dreadnought 2011-04-19
  • 打赏
  • 举报
回复
ExitThread?TerminateThread?
Eleven 2011-04-19
  • 打赏
  • 举报
回复
没有CloseThraed这个函数
你想说的是CloseHandle()吧
安乐风流 2011-04-19
  • 打赏
  • 举报
回复
CloseHandle()。 不一定会关闭线程的,只会将计数器减1,当计数器为0时才会关闭线程。
xi52qian 2011-04-19
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 lorenzhai 的回复:]
Handle,是一个内核对象在Win32中的一种表示方法,该内核变量同时有个引用计数。
CloseHandle,一般用来对内核变量进行操作,调用一次这个函数,对应内核对象的引用计数就减1。如果计数到零,系统就销毁该内核对象(这个跟COM接口的引用计数很类似)

对于CreateThread,调用后,有两个线程堆栈,一个用户态的,一个内核态的,内核的Ethread,Kthread结构里包含了该……
[/Quote]
说得很对~
就是没必要立刻调用CloseHandle什么时候不用什么时候释放就可以了
xi52qian 2011-04-19
  • 打赏
  • 举报
回复
CloseHandle是关闭句柄(包括线程句柄),线程句柄和线程是2回事,创建线程的时候系统会给进程的内核表中添加线程句柄,比如CreateThread函数返回的就是子线程的句柄,如果你在主线程不用操作子线程的话,可以马上关闭,调用CloseHandle//关闭句柄不会对自线程的运行造成任何影响,相反如果子线程关闭你不调用CloseHandle来关闭句柄就会内存泄漏。(具体请看Windows核心编程第三章)。
ExitThread和_endthread都是关闭线程的函数。
关闭线程的最好方式是让线程函数自己return退出。
用ExitThread和_endthread会造成线程退出时候不会调用类的析构函数。
用TerminateThread强制退出,不仅析构函数没有调用,连栈的内存也不会被释放。
具体请看书吧~
xengine-qyt 2011-04-19
  • 打赏
  • 举报
回复
线程不在执行的时候需要关闭
Loren 2011-04-19
  • 打赏
  • 举报
回复
Handle,是一个内核对象在Win32中的一种表示方法,该内核变量同时有个引用计数。
CloseHandle,一般用来对内核变量进行操作,调用一次这个函数,对应内核对象的引用计数就减1。如果计数到零,系统就销毁该内核对象(这个跟COM接口的引用计数很类似)

对于CreateThread,调用后,有两个线程堆栈,一个用户态的,一个内核态的,内核的Ethread,Kthread结构里包含了该线程对象的引用计数。默认是2,所有线程创建出来后,要立刻调用一下CloseHandle,最后结束时再调用一下CloseHandle,这样才不会导致内核对象泄露(Non-Paged Pool)

记得:
用CloseHandle来关闭的,在系统内核都一个内核对象与之对应。如File,MapFile,Process,Thread,Event,etc。
96掌门师兄 2011-04-19
  • 打赏
  • 举报
回复
一般句柄在不需要的时候就使用CloseHandle()释放。。

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧