【发布时间】:2017-03-30 14:59:07
【问题描述】:
我正在 Linux 下用 C++ 开发一个共享库。
当有新的构建可用时,共享库代码有没有办法自行重新加载?
我正在考虑使用dlclose 和dlopen 重新加载,但前者需要一个只能被正在运行的进程访问的句柄。
知道如何从共享库代码中检索该句柄吗?对整个想法有更好的解决方案吗?
我知道热插拔很危险,但这会使开发和测试变得更加容易。
【问题讨论】:
我正在 Linux 下用 C++ 开发一个共享库。
当有新的构建可用时,共享库代码有没有办法自行重新加载?
我正在考虑使用dlclose 和dlopen 重新加载,但前者需要一个只能被正在运行的进程访问的句柄。
知道如何从共享库代码中检索该句柄吗?对整个想法有更好的解决方案吗?
我知道热插拔很危险,但这会使开发和测试变得更加容易。
【问题讨论】:
当您重建共享库时,其导出的符号地址可能会发生变化。
因此,在重新加载共享库时,必须重新解析其用户导入的所有符号。
必须在卸载共享库之前销毁具有驻留在共享库中的虚拟表的对象1。
如果库是由ld.so 自动加载的,则无法重新加载。
如果应用程序使用dlopen 加载共享库,则必须再次运行相同的代码以重新加载库并重新解析符号。
还有可能使事情复杂化的线程本地存储。
换句话说,在应用程序不知道的情况下重新加载共享库工作太复杂了。
1我曾经调试过一个有趣的错误。有一个共享库在运行时使用dlopen 加载并在使用后卸载。该应用程序稍后会在终止期间在std::cout 析构函数中崩溃。原来共享库正在将 Boost.Date_Time 对象输出到std::cout。这样做时,库将 std::cout.imbue 一个新的语言环境,其中包含来自 Boost.Date_Time 的自定义构面对象(构面具有虚函数)。当库被卸载时,facet 对象仍然由该语言环境拥有,但它的 vtable 指针指向卸载的共享库中的虚拟表,这将导致销毁 facet 时崩溃。
【讨论】: