【问题标题】:Recycle-safe thread ID's and when thread stack gets freed?回收安全的线程 ID 和线程堆栈何时被释放?
【发布时间】:2010-08-17 12:11:52
【问题描述】:

时,为线程保留/提交的堆栈是否被释放
  • 线程终止
  • 线程对象被销毁
    (即线程终止,线程的所有句柄都关闭)

?

更广泛地说,是否存在与已终止但由于存在有效句柄而仍然存在的线程相关联的大量资源?


原因:我需要修改一种“作用域单例”,所以它不会返回单个对象,而是每个线程的对象。我不能依赖线程创建/终止通知,更不用说进程范围的通知了。

目前,我将对象存储在map<ThreadID, Object> 中,并使用适合我的应用程序的缓存清理策略。为了保护自己免受操作系统“回收”线程 ID 的影响,我保持打开线程的句柄。 (推荐

在某些极端情况下,副作用会是为长期终止的线程持有打开的句柄。

【问题讨论】:

    标签: windows multithreading memory-management


    【解决方案1】:

    根据 Richter 和 Nasarre 的 "Windows VIA C/C++"(任何 C++ Windwos 程序员的必备书籍)第 154 页:

    终止线程

    一个线程可以在四个 方式:

    • 线程函数返回。 (强烈建议这样做。)
    • 线程通过调用 ExitThread 函数杀死自己。 (避免这种 方法。)
    • 同一进程或另一个进程中的线程调用 TerminateThread 功能。 (避免使用这种方法。)
    • 包含线程的进程终止。 (避免使用这种方法。)

    线程函数返回

    你应该始终设计你的线程 函数,以便它们在您返回时返回 希望线程终止。这是 唯一能保证所有 你线程的资源被清理了 正确。

    让你的线程函数返回 确保以下内容:

    • 在您的线程函数中创建的所有 C++ 对象都将被销毁 正确地通过它们的析构函数。
    • 操作系统将正确释放线程使用的内存 堆栈。
    • 系统会设置线程的退出代码(维护在线程的 内核对象)到你的线程 函数的返回值。
    • 系统将减少线程内核对象的使用计数。

    ExitThread 函数

    您可以通过调用 ExitThread 来强制终止您的线程:

    VOID ExitThread(DWORD dwExitCode);

    这个函数终止线程 并导致操作系统 清理所有操作系统 使用的资源 线。但是,您的 C/C++ 资源 (如 C++ 类对象)不会 被摧毁。为此,它是 简单地从你的 线程函数而不是调用 自己退出线程。

    当然,你使用 ExitThread 的 dwExitCode 参数告诉 系统设置什么线程的退出 代码到。 ExitThread 函数确实 不返回值,因为线程 已终止且无法执行任何 更多代码。

    注意推荐的方法 线程终止是通过让其 线程函数简单地返回(如 在上一节中描述)。 但是,如果您使用该方法 在本节中描述,请注意 ExitThread 函数是 杀死线程的 Windows 函数。 如果你正在编写 C/C++ 代码,你 永远不要调用 ExitThread。反而, 你应该使用 C++ 运行时 库函数_endthreadex。如果你 不要使用微软的 C++ 编译器, 您的编译器供应商将拥有自己的 替代退出线程。任何 这个替代方案是,你必须使用它。

    TerminateThread 函数

    调用 TerminateThread 也会杀死一个线程:

    BOOL 终止线程(句柄 hThread, DWORD dwExitCode);

    与 ExitThread 不同,它总是杀死 调用线程 TerminateThread 可以杀死任何线程。线程 参数标识句柄 要终止的线程。当。。。的时候 线程终止,它的退出代码 成为您传递的值 dwExitCode 参数。此外,该 线程的内核对象有它的用途 计数减少。

    注意 TerminateThread 函数是 异步。也就是说,它告诉 您希望线程到的系统 终止但线程不是 保证被时间杀死 函数返回。如果你需要 确定线程有 终止,你可能想打电话 WaitForSingleObject 或类似的函数, 传递线程的句柄。

    精心设计的应用程序永远不会使用 这个函数是因为线程正在 终止没有收到通知 它快死了。线程不能 正确清理,它不能 防止自己被杀死。

    注意当线程因返回而死时 或调用 ExitThread,堆栈为 线程被破坏。然而,如果 使用 TerminateThread,系统 不会破坏线程的堆栈 直到拥有 线程终止。微软故意 在此实现了 TerminateThread 方式。如果其他仍在执行的线程 是在参考值 强行杀死线程的堆栈,这些 其他线程会提高访问权限 违规行为。通过离开被杀者 线程在内存中的堆栈,其他 线程可以继续执行 很好。

    此外,动态链接库 (DLL)通常会收到通知 当线程终止时。如果一个 线程被强行杀死 TerminateThread,然而,DLL 会 未收到此通知,即 会妨碍正确的清理。

    线程终止时

    当一个 线程终止:

    拥有的所有用户对象句柄 线程被释放。在 Windows 中,大多数 对象归进程所有 包含创建的线程 对象。但是,一个线程拥有两个 用户对象:窗口和挂钩。什么时候 线程死了,系统 自动销毁任何窗口和 卸载任何已创建的钩子 或由线程安装。其他 只有当对象被销毁时 拥有进程终止。

    线程的退出代码从 STILL_ACTIVE 到传递给的代码 ExitThread 或 TerminateThread。

    线程内核对象的状态 发出信号。

    如果线程是最后一个活动的 进程中的线程,系统 认为进程终止为 好吧。

    线程内核对象的使用计数 减 1。

    当一个线程终止时,它的 关联线程内核对象 不会自动释放 直到所有优秀的参考文献 对象已关闭。

    一旦线程不再运行, 没有太多其他线程 系统可以用线程的 处理。然而,这些其他线程 可以调用 GetExitCodeThread 来检查 线程是否由 hThread 已终止,如果已终止, 确定其退出代码:

    BOOL GetExitCodeThread( 句柄 hThread, PDWORD pdwExitCode);

    退出代码值在 pdwExitCode 指向的 DWORD。如果 线程尚未终止时 GetExitCodeThread 被调用, 函数用 STILL_ACTIVE 标识符(定义为 0x103)。如果函数成功, 返回 TRUE。

    【讨论】:

    • 有点多,但包含我正在寻找的内容。谢谢!
    【解决方案2】:

    也许您应该使用pthread_getspecificpthread_setspecificpthread_key_create 来管理您的每线程单例。

    【讨论】:

    • 我希望我可以 - 我必须处理使用不同/未知线程库的调用者,不确定是否涉及 pthreads 会使事情变得更简单。不过,感谢您指出。
    猜你喜欢
    • 1970-01-01
    • 2010-10-21
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 2015-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多