我需要调用 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 之前 - 会发生啥?

Windows C++ - 使用 CloseHandle 关闭线程

线程创建后为什么要调用CloseHandle

如果未使用 CloseHandle 正确关闭,则重新打开串行端口失败