两次加载共享库

时间:2018-02-19 10:59:38

标签: c ubuntu shared-libraries

我正在尝试在C中加载共享库两次:

lib1 = dlopen(„mylib.so", RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);
lib2 = dlopen(„mylib.so", RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);

我想要的是lib1和lib2有不同的地址空间,以便它们可以做不同的事情。目前,我能实现这一目标的唯一方法是复制mylib,使代码如下所示:

lib1 = dlopen(„mylib.so", RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);
lib2 = dlopen(„mylib2.so", RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);

在有限的范围内,这对我来说很好。但是,我有一个应用程序,它使用库一般次数,这使得复制库很麻烦。

是否有更好的方法在每次加载库时都有一个单独的地址空间?

编辑:

我希望多次加载库,因为我的应用程序正在处理一种消息队列。消息队列中的项目引用共享库的名称(例如mylib),并包含一组应由库处理的数据。我想在多线程环境中处理MQ,在自己的线程中运行对库方法的每次调用。 只要MQ只包含对库的调用一次,一切都按预期工作。但是,当我有两个使用相同库的项目时,事情开始变得奇怪。

3 个答案:

答案 0 :(得分:3)

动态加载代码的整个想法是,您可以共享它,特别是与其他进程共享它。出于这个原因,我认为不可能真正加载库两次。

虽然有很多方法可以解决这个问题。一种可能是欺骗动态链接器第二次加载它。复制库是您已经找到的一种方法。我也可以想象很难找到工作的链接。

但是,我认为如果你在这里使用流程会更好。我认为有两种方法可以实现我的目标:分叉一个单独的进程或创建一个单独的init函数。

对于单独的过程,您只需fork(),在父和子之间设置适当的IPC机制后,而不是第二次加载库。由于fork创建了一个新进程,它会收到自己的内存空间,并且事物保持独立。作为IPC,我建议使用某种中间件,如ZeroMQ,dbus或XMLRPC。

另一个选项是创建单独的init函数。为此,您不是将库的状态创建为全局变量,而是将它们一起放入结构中。然后,在该init函数中,您创建该结构的实例,将其设置并返回其地址。之前在全局状态下运行的所有其他功能现在接收该结构的地址作为附加(通常的第一)参数。您可以简单地调用init函数两次来设置单独的环境,而不是两次加载库。

答案 1 :(得分:2)

不确定为什么这个问题被低估了,这是完全合理的。

您需要使用dlmopen来实现这种隔离:

// No need for RTLD_LOCAL, not sure about RTLD_DEEPBIND
lib1 = dlmopen (LM_ID_NEWLM, "mylib.so", RTLD_LAZY | RTLD_DEEPBIND);

答案 2 :(得分:0)

  

是否有更好的方法在每次加载库时都有一个单独的地址空间?

实际上,virtual address space属于process(因此对于其中的所有线程),不属于到共享库(使用几个该虚拟地址空间的片段。)

对于pid 1234的流程,请使用pmap(1)(作为pmap 1234)或proc(5)(例如,尝试cat /proc/1234/maps ...)

你真的应该避免dlopen(3) - 相同的共享库“两次”(这很难,故意;你可以使用符号链接和{ {1}}多个符号链接到同一个共享对象,但不应该执行此操作,例如,因为dlopen数据将“加载两次”并且后果将发生)。为避免这种情况发生,dynamic loader使用了reference counting种技术......

另请阅读Drepper的How to Write Shared Libraries

  

是否有更好的方法在每次加载库时都有一个单独的地址空间?

然后,您需要不同的进程,每个进程都有自己的虚拟地址空间。您将使用inter-process communication:请参阅pipe(7)fifo(7)socket(7)unix(7)shm_overview(7)sem_overview(7)等...