在 Win32/MFC 和 POSIX 中,线程会自行清理吗?

Posted

技术标签:

【中文标题】在 Win32/MFC 和 POSIX 中,线程会自行清理吗?【英文标题】:Do threads clean-up after themselves in Win32/MFC and POSIX? 【发布时间】:2009-09-28 20:39:27 【问题描述】:

我正在使用 C++ 和 Boost 开发一个多线程程序。我正在使用辅助线程来急切地异步初始化资源。如果我分离线程并且对线程的所有引用超出范围,我是否泄漏了任何资源?或者线程是否在自身之后进行清理(即它的堆栈和自身所需的任何其他系统资源)?

根据我在文档中看到的内容(以及我 8 年前从 pthreads 中看到的内容),不需要进行明确的“破坏线程”调用。

我希望线程异步执行,当需要使用资源时,我会检查是否发生错误。粗略的代码如下所示:

//Assume this won't get called frequently enough that next_resource won't get promoted
//before the thread finishes.
PromoteResource() 
   current_resource_ptr = next_resource_ptr;
   next_resource_ptr.reset(new Resource());
   callable = bind(Resource::Initialize, next_resource); //not correct syntax, but I hope it's clear
   boost::thread t(callable);
   t.start();

当然——我知道正常的内存处理问题仍然存在(忘记删除、错误的异常处理等)...我只需要确认线程本身不是“泄漏”。

编辑:澄清一点,我想确保这在技术上不是泄漏:

void Run() 
   sleep(10 seconds);


void DoSomething(...) 
   thread t(Run);
   t.run();
 //thread detaches, will clean itself up--the thread itself isn't a 'leak'?

我相当肯定一切都会在 10 秒后清理干净,但我想绝对确定。

【问题讨论】:

我真的不明白你的问题:线程堆栈上的东西当然会在退出线程入口函数时被清理干净。堆上的东西或任何资源当然不会在线程退出时被释放。 Boosts 线程对象当然应该在线程退出时自行删除 - 否则这对我来说没有意义。 基本上,我想确保没有我应该调用的“破坏线程”方法被我忽略了。 【参考方案1】:

线程的堆栈在退出时会被清理,但不会清理其他任何东西。这意味着它在堆上或其他任何地方(例如在预先存在的数据结构中)分配的任何东西都会在它退出时留下。

此外,任何操作系统级别的对象(文件句柄、套接字等)都将留在周围(除非您使用在其析构函数中关闭它们的包装器对象)。

但是,频繁创建/销毁线程的程序可能应该主要释放它们在同一个线程中分配的所有内容,因为这是让程序员保持理智的唯一方法。

【讨论】:

Mark:听起来标准内存管理规则适用。唯一特定于线程本身的“资源”是它的堆栈,你说线程的堆栈已被清理。至于其他资源,我使用 RIAA 技术(或等效包装器)来避免泄漏。 如果您使用的是 RIAA 对象,那么在线程退出之前,在 main 函数结束时清除其堆栈时,该线程完全“拥有”的任何东西都应该被自动抛出。唯一需要注意的是循环引用,以及不完全“拥有”的东西,例如在应用程序的其他地方具有强共享引用的东西。【参考方案2】:

如果我没记错的话,在 Windows Xp 上,进程使用的所有资源都会在进程终止时释放,但线程并非如此。

【讨论】:

【参考方案3】:

是的,资源会在线程终止时自动释放。拥有后台线程是一件非常正常且可以接受的事情。

要在线程后清理,您必须加入或分离它(在这种情况下,您不能再加入它)。

这是来自 boost thread docs 的引述,它在一定程度上解释了这一点(但不完全)。

当 boost::thread 对象 表示一个执行线程是 被破坏的线程变得分离。 一旦线程被分离,它将 继续执行直到 调用函数或可调用 施工提供的对象有 完成,或者程序是 终止。线程也可以 通过显式调用 detach() 成员函数 boost::thread 对象。在这种情况下, boost::thread 对象停止 表示现在分离的线程,并且 而是代表 Not-a-Thread。

为了等待一个线程 执行完成,join() 或 timed_join() 的成员函数 必须使用 boost::thread 对象。 join() 将阻塞调用线程 直到由 boost::thread 对象已完成。如果 代表的执行线程 boost::thread 对象已经 完成,或 boost::thread 对象 表示 Not-a-Thread,然后 join() 立即返回。 timed_join() 是 类似,除了调用 timed_join() 也将返回,如果 正在等待的线程不 到指定时间时完成 已过。

【讨论】:

【参考方案4】:

在 Win32 中,一旦线程的 main 函数(在文档中称为 ThreadProc)完成,线程就会被清理。当然,您在 ThreadProc 中分配的任何资源都需要明确清理。

【讨论】:

以上是关于在 Win32/MFC 和 POSIX 中,线程会自行清理吗?的主要内容,如果未能解决你的问题,请参考以下文章

mingw-w64线程模型:posix vs win32(posix允许使用c++11的std:: thread,但要带一个winpthreads,可能需要额外dll)

在无模式对话框中阻止 ESC 和 Enter 键(Win32,非 MFC)

从 C# 访问 Win32/MFC “Stuff”

如何本地化 win32(非 MFC)DLL

使用 Win32/MFC 关闭并等待子框架窗口的最佳方法

Win32/MFC/COM学习推荐书籍