【问题标题】:When a process ends, what happens to a thread that is in the middle of Sleep()?当一个进程结束时,处于 Sleep() 中间的线程会发生什么?
【发布时间】:2014-02-18 17:14:53
【问题描述】:

我正在使用一个开始和结束线程的类。线程是在构造函数中创建的。只要标志为 TRUE,线程函数就会继续循环。标志是类的静态成员。解构器将标志设置为 FALSE。这样,类的每个实例都有一个关联线程,该线程在实例的生命周期内运行。

我试图了解解构器运行时会发生什么,以及这是否是结束线程的好方法。我对多线程没有太多经验。

这就是我认为会发生的事情。在解构器内部,标志将设置为 FALSE。让我们假设 Sleep() 正在无限运行。对象被销毁,但标志仍然存在于内存中,因为它是静态的。但是整个过程正在结束,比方说,所以在某些时候静态标志会消失。标志会在线程之前消失吗?如果线程被进程结束强制返回,线程甚至不再关心标志吗?我不知道此时会发生什么。

我在 Visual Studio 2010 中使用 Visual C++。

【问题讨论】:

  • 你可以在解构器中更改标志后等待线程完成。

标签: c++ c multithreading visual-c++ process


【解决方案1】:

请注意,当其他线程仍在使用该对象(不是静态标志)时运行析构函数将产生未定义的结果。

想想当线程正在处理而不是检查活动标志时会发生什么,机会很小吧。

最好写一个 stop(bool wait) 函数,所以如果调用析构函数并且需要自动清理,你设置标志停止,并阻塞直到线程设置另一个标志为“停止”,或者只需使用 pthread_join 加入该线程(不推荐,见下文)。

此外,当您阻止优雅终止时,您还可以设置超时,并在出现问题时强制终止线程(并生成调试警报)。

【讨论】:

  • 通常的口头禅“不要在 GUI 事件处理程序中进行阻塞调用”也适用于关机期间。
  • 是的,GUI线程不应该被阻塞,你应该停止线程,并等待它真正停止,然后以异步方式(例如使用消息)析构函数。在析构函数中停止线程应该是安全的最后手段。
【解决方案2】:

在 Windows 上,线程的生命周期小于或等于创建它的进程。因此,一旦进程结束,线程也会结束。

在该进程中的所有线程终止之前,正常的进程关闭不会完成。因此,在这种情况下,将设置标志,主线程可能会终止,但创建的后台线程将继续运行。最终他们将看到标志的FALSE 值,退出他们的循环,完成并且进程关闭将完成。

【讨论】:

  • 最终您在等待卸载 DLL 时已被 Windows 停止的线程时遇到死锁。请参阅 MSDN 中的 Loadlibrary()/FreeLibrary()。去过那里,经历过。最佳实践是(1)永远不要等待INFINITEly 等待模块卸载和(2)在卸载创建自己的线程的模块之前始终调用/使用清理例程。会省去一些麻烦。
【解决方案3】:

这取决于“解构器”是否真正运行。

如果您尝试“解构”您在某些“OnClose”事件处理程序中描述的对象,设置静态标志将指示线程在检查时终止。如果它们不这样做,线程将继续休眠,(或停留在任何阻塞的调用上,或继续运行代码)。

如果您不采取进一步措施等待对象线程终止,主 GUI 线程将继续运行,销毁其所有 GUI 对象等,并调用 ExitProcess()。

调用 ExitProcess() 后,操作系统将停止进程的所有线程,无论它们处于何种状态,然后再释放任何内存(例如包含您的标志的内存)。

调用 ExitProcess() 的线程永远不会将控制权返回给它。属于同一进程且未在另一个内核上运行的其他线程具有其状态集,因此它们永远不会再次运行。属于同一进程并在另一个内核上运行的其他线程会将它们正在运行的内核硬件中断以停止线程。

flag会在线程之前消失吗?

没有。在释放承载标志的内存之前,线程将停止。

如果您不希望发生这种强制终止,您必须采取措施等待对象线程的实际终止。您必须通过在 OnClose 处理程序中设置适当的 CloseAction 来延迟主 GUI 线程调用 ExitProcess。只有当所有对象线程都终止并且对象的析构函数完成时,GUI 线程才应该关闭/释放自己。

如果我真的、真的、真的必须这样做,宁愿通过 PostMessaging 向主 GUI 线程发送“WM_THREADGONE”Windows 消息来完成(作为对象线程在实际终止自身之前的最后一个操作),并且在消息处理程序中将“threadCount”倒数到零,因此保持 GUI 线程可用于处理消息,直到所有对象线程都自行终止。硬等待机制,如 Join(),只是死锁生成器,具有巨大的关闭问题容量,不应该使用。

我通常尝试通过设计我的应用程序来解决所有线程终止问题,以便突然的、非自愿的线程终止是可接受的操作,然后让 Exitprocess() 解决所有问题。这并不总是可行的,但如果你能侥幸逃脱,那就更安全了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-06
    • 1970-01-01
    • 1970-01-01
    • 2011-01-24
    • 2016-05-20
    • 1970-01-01
    • 2015-05-26
    • 1970-01-01
    相关资源
    最近更新 更多