在Linux上关于RTLD_LOCAL和dynamic_cast的问题

4
我们有一个插件,由我们应用程序中的几个共享库构成,需要在应用程序运行时更新。出于性能考虑,在卸载旧插件之前,我们加载并开始使用新插件,只有当所有线程都使用旧插件完成后,我们才卸载它。由于新插件和旧插件的库中具有相同的符号,因此我们使用dlopen()RTLD_LOCAL。如果不这样做,新插件的调用将意外地从旧插件的内部函数转到符号。
插件的一个库对由插件的另一个库创建的对象进行dynamic_cast()。这在HP-UX、AIX、Solaris和Windows上可以工作,但在Linux上不行。据我所知,这是因为所有这些操作系统(编译器)都使用类名来比较类型(在dynamic_cast()中),但Linux使用名称字符串地址来执行此比较(以提高性能),由于每个库都有自己的type_info对象(因为它是使用RTLD_LOCAL加载的),因此地址是不同的,因此等同类型似乎与dynamic_cast()不相等。
有没有办法执行以下操作之一:
  • 仅使type_info对象加载为如果提供了RTLD_GLOBAL
  • 使编译器使用类名比较而不是type_info地址来比较类型之间的差异。
?我们正在使用的编译器是:
$ icpc -V
Intel(R) C++ Intel(R) 64 Compiler XE for applications running on Intel(R) 64, Version 12.0.0.084 Build 20101006
Copyright (C) 1985-2010 Intel Corporation.  All rights reserved.
2个回答

5

好的,我们最终做的是在问题周围进行了一些处理。

我们为想要进行dynamic_cast()的类添加了两个静态函数:

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

这些功能被实现在cpp文件中,其中保留了newdynamic_cast()type_info对象在同一个库中,从而使dynamic_cast()解决了问题。
这种解决方案已足够适用于我们的特定情况,但如果有更普遍的解决方案,我们将非常欢迎。
我们发现的另一种选择是将类的所有实现放在cpp文件中,这样typeinfo符号只出现在一个库中,而其他所有库都只引用它。这会导致dynamic_cast()成功。

3
很遗憾,由于type_info结构是创建它们的库中的弱符号局部变量,因此很难使dynamic_cast正常工作。但你可以尝试操作类vtable(和type_info)实例化的位置;在GCC上,你可以通过确保类中第一个非内联函数(按定义顺序)仅在共享依赖库中定义来实现这一点。如果你的类没有非内联函数,则创建一个虚拟函数来强制进行此生成。但请注意,我未经测试,不能保证其有效性。此外,这是与编译器相关的。我不知道Intel的编译器做了什么。
当然,你也可以使用类名实现自己的动态类型转换机制;还有许多库也是这样做的,例如Qt的qobject_cast

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接