c++ - 创建自己的线程的 native 共享库可以(应该吗?)支持退出 'without warning' 的使用进程?

标签 c++ linux windows multithreading shared-libraries

我开发的产品通常构建为共享库。

使用应用程序将加载它,创建一些句柄,使用它们,并最终释放所有句柄并卸载库。

库会创建一些后台线程,这些线程通常会在释放句柄时停止。

现在的问题是,一些消费应用程序的行为不是很好,并且在某些情况下(取消、错误等)无法释放句柄。最终,我们库中的静态析构函数会运行,并在它们尝试与(现已死亡的)后台线程交互时崩溃。

一种可能性是不让任何全局对象具有析构函数,这样可以避免在静态析构期间运行库中的任何代码。这可能会解决进程退出时的崩溃,但它会在应用程序简单地卸载库而不释放句柄(而不是退出)的情况​​下引入泄漏和崩溃,因为我们无法确保后台线程实际上是在他们正在运行的代码被卸载之前停止。

更重要的是,据我所知,当 main() 退出时,所有其他线程都将被杀死,无论它们当时恰好在何处,这可能会导致锁被锁定,并且不变量被破坏(例如,在堆管理器中) .

鉴于此,尝试支持这些有缺陷的应用程序是否有意义?

最佳答案

是的,您的库应该允许进程在没有警告的情况下退出。也许在理想的世界中,每个使用您的库的程序都会仔细跟踪句柄并在它出于任何原因退出时将它们全部释放,但实际上这不是一个现实的要求。触发程序退出的代码路径可能是一个共享组件,它甚至不知道您的库正在使用中!

无论如何,您当前的体系结构很可能存在更普遍的问题,因为静态析构函数与其他线程交互本质上是不安全的。

来自 DllMain entry point在 MSDN 中:

Because DLL notifications are serialized, entry-point functions should not attempt to communicate with other threads or processes. Deadlocks may occur as a result.

If your DLL is linked with the C run-time library (CRT), the entry point provided by the CRT calls the constructors and destructors for global and static C++ objects. Therefore, these restrictions for DllMain also apply to constructors and destructors and any code that is called from them.

特别是,如果您的析构函数试图等待您的线程退出,那么在线程仍在运行时显式卸载库的情况下,这几乎肯定会死锁。如果析构函数不等待,当线程运行的代码消失时,进程就会崩溃。我不确定你为什么还没有看到那个问题;也许你正在终止线程? (这也不安全,尽管出于不同的原因。)

有很多方法可以解决这个问题。可能最简单的就是您已经提到的那个:

One possibility is to not have any global objects with destructors, and so to avoid running any code in the library during static destruction.

你接着说:

[...] but it would introduce leaks and crashes in the scenario where the application simply unloads the library without freeing the handles [...]

那不是你的问题!仅当应用程序明确选择这样做时才会卸载该库;显然,与前面的情况不同,有问题的代码知道您的库存在,因此您要求它在执行此操作之前关闭所有句柄是完全合理的。

然而,理想情况下,您应该提供一个自动关闭所有句柄的取消初始化函数,而不是要求应用程序单独关闭每个句柄。显式初始化和取消初始化函数还允许您安全地设置和释放全局资源,这通常比在每个句柄的基础上进行所有设置和拆卸更有效,并且肯定比使用全局资源更安全对象。

(有关适用于静态构造函数和析构函数的所有限制的完整描述,请参阅上面的链接;它们非常广泛。在显式初始化例程中构造所有全局变量,并在显式取消初始化例程中销毁它们,避免了整个过程乱七八糟的生意。)

关于c++ - 创建自己的线程的 native 共享库可以(应该吗?)支持退出 'without warning' 的使用进程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41175724/

相关文章:

c++ - 未定义对 `WinMain@16' 的引用

c - 内核领域中的错误处理/检查

windows - Websocket 服务器在约 600 个连接后停止接受

windows - 可执行文件的文件大小怎么会这么小?

C++ 加减 100 位数字

c++ - 继承与实例

c++ - 第一次读取时文件读取速度较慢,但​​连续读取时速度很快

c++ - 控制外部库的输出

windows - 在 Windows App 上提交基于 Qt 的应用程序

c++ - 如何将指数形式的浮点值转换为点表示法?