我需要调用 CloseHandle 吗?
Posted
技术标签:
【中文标题】我需要调用 CloseHandle 吗?【英文标题】:Do I need to call CloseHandle? 【发布时间】:2015-09-01 17:10:57 【问题描述】:我有代码创建一个线程并在程序结束时用CloseHandle
关闭它。
int main()
....
HANDLE hth1;
unsigned uiThread1ID;
hth1 = (HANDLE)_beginthreadex( NULL, // security
0, // stack size
ThreadX::ThreadStaticEntryPoint,
o1, // arg list
CREATE_SUSPENDED, // so we can later call ResumeThread()
&uiThread1ID );
....
CloseHandle( hth1 );
....
但是为什么我需要关闭手柄呢?如果我不这样做会怎样?
【问题讨论】:
您是在一般情况下询问当您省略CloseHandle
时会发生什么,还是对于关闭从 _begintheadex
返回的句柄的特定情况?
我问的是一般情况
我可以建议实施 - 例如用于调试配置构建 - _CRTDBG_MAP_ALLOC。你可以让你的软件告诉你是否有内存泄漏。自己彻底清理总是比让系统在退出时清理要好。
【参考方案1】:
但是为什么我需要关闭句柄呢?
句柄是占用内核和用户空间内存的有限资源。保持句柄处于活动状态不仅需要整数值的存储空间,而且还意味着内核必须保留线程信息(例如用户时间、内核时间、线程 ID、退出代码),并且它无法回收线程 ID,因为您可以使用该句柄查询它。 因此,最好在不再需要句柄时关闭它们。
这是您根据 API 合同要做的事情(但您当然可以违反该合同)。
如果我不这样做会怎样?
好吧,说实话……没什么。您将泄漏该句柄,但对于 一个句柄,其影响将无法衡量。当您的进程退出时,Windows 将关闭句柄。
不过,在正常情况下,您应该关闭不再需要的句柄,就像释放已分配的内存一样(即使在您的进程退出时操作系统也会释放它)。
尽管不显式释放资源甚至可能被视为“优化”,但为了获得正确程序,应该始终这样做。正确性第一,优化第二。 此外,您越早释放资源(无论它多么小),它就可以越早再次供系统重新使用。
【讨论】:
我发现不以某种“魔法”方式关闭句柄会损坏配置文件或数据库。所以,看来,这不是事实。 @vico:在一个格式良好的程序中,这不应该发生(即不可能)。但当然,您可能会在错误的程序中意外使用有效句柄(您尚未关闭)的句柄值。除此之外,如果您不关闭(或至少同步)C stdio 句柄并且您的进程意外终止,您还可能丢失数据并获得损坏的、写入一半的文件。原因是您的写入被缓冲在用户空间中,一旦进程终止,就会发生kaboom(理论上重叠写入可能会发生类似的情况,但由于设计原因在实践中不会发生)。 然而,线程句柄不可能发生这种情况。此外,对于 Windows 文件句柄,这些都不应该是可能的(写入成功或失败,一旦成功,责任就在于操作系统)。【参考方案2】:这里有一个主题可以回答您的问题: Can I call CloseHandle() immediately after _beginthreadex() succeeded?
您好。
【讨论】:
【参考方案3】:是的,您需要在某个时候关闭句柄,否则您将泄漏有限的操作系统资源。
【讨论】:
【参考方案4】:我可以建议为您的手柄创建一个 RAII 包装器吗?基本上,您编写一个包装器来存储您创建的句柄并在其析构函数中调用 CloseHandle。这样您就不必担心忘记关闭它(当它超出范围时它会自动关闭)或如果在打开句柄和关闭它之间发生异常时泄漏句柄。
【讨论】:
【参考方案5】:如果您不关闭句柄,那么它将保持打开状态,直到您的进程终止。根据手柄后面的内容,这可能很糟糕。资源通常与句柄相关联,并且在程序终止之前不会被清理;如果您只使用几个手柄并且这些手柄恰好是“轻量级”,那么这并不重要。其他句柄,例如文件句柄,对保持句柄打开有其他副作用,例如锁定打开的文件直到您的进程退出。这对用户或其他应用程序来说可能非常烦人。
一般情况下,最好清理所有句柄,但在进程结束时,所有句柄都会被 Windows 关闭。
【讨论】:
以上是关于我需要调用 CloseHandle 吗?的主要内容,如果未能解决你的问题,请参考以下文章
VC++中通过CreateThread创建的线程,当线程入口函数执行完后,线程自己会关闭吗?
CreateProcess .. WaitForSingleObject .. CloseHandle 调用的最佳 try..finally 位置
互斥体上的 CloseHandle,在 ReleaseMutex 之前 - 会发生啥?