Linux上的RTLD_LOCAL和dynamic_cast

我们有一个插件,它是由我们的应用程序中的一些共享库构build而成的,我们需要在应用程序运行时进行更新。 出于性能方面的原因,我们在卸载旧插件之前加载并开始使用新插件,并且只有在使用旧插件完成所有线程时,我们才能卸载它。 由于新插件和旧插件的库在它们中具有相同的符号,我们使用RTLD_LOCAL进行dlopen()。 如果我们不把新的插件从内部函数偶然调用到旧插件的符号。

插件的一个库执行dynamic_cast()到由另一个插件库创build的对象。 这适用于HP-UX,AIX,Solaris和Windows,但不适用于Linux。 据我所知,这是因为所有这些操作系统(编译器)都使用类的名称来比较types(在dynamic_cast()中),但是Linux使用type_info对象地址来进行比较(以提高性能),并且由于每个库有它自己的type_info对象(因为它是用RTLD_LOCAL加载的)地址是不同的,因此相同的types似乎不等于dynamic_cast()。

有没有办法做到以下一种:

  • 只提供类似信息对象,就好像提供了RTLD_GLOBAL一样。
  • 使编译器使用类名比较而不是type_info地址来比较types。

? 我们正在使用的编译器是:

$ icpc -V英特尔(R)C ++英特尔(R)64编译器XE,适用于在英特尔(R)64版本12.0.0.084版本20101006上运行的应用程序版权所有(C)1985-2010英特尔公司。 版权所有。

Solutions Collecting From Web of "Linux上的RTLD_LOCAL和dynamic_cast"

好的,我们终于做了一些解决这个问题的方法。

我们在类中加入了我们想要的dynamic_cast()两个静态函数:

static MyClass* doNew(); static MyClass* doDynCast(MyBase*); 

这些是在cpp文件中实现的,它将new和dynamic_cast()保存在同一个lib中,从而使dynamic_cast()可以解决这个问题。

这个解决方案对于我们的具体案例来说已经足够了,但是如果有人有更通用的解决方案,它将会受到欢迎

我们发现的另一个选择是将类的所有实现放在cpp文件中,这使得typeinfo符号只出现在一个库中,而其他所有库都只引用它。 这导致dynamic_cast()成功。

不幸的是,因为type_info结构是创建它们的库的本地弱符号,所以使dynamic_cast无法正常工作。 你可以尝试操作类vtable(和type_info)被实例化的地方; 在GCC上,这可以通过确保类中的第一个非内联函数(按定义顺序)只在公共共享依赖库中定义。 如果你的类没有非内联函数,那么创建一个虚拟类来强制这一代发生。 但请注意,我没有测试过这个,所以不能保证它能正常工作。 另外,这是依赖于编译器的; 我不知道英特尔的编译器是做什么的。

当然,您可以使用类名实现自己的替代动态转换机制; 还有一些库也在做这个,比如Qt的qobject_cast 。