加载共享库两次
Loading shared library twice
我试图在 C 中加载共享库两次:
lib1 = dlopen("mylib.so", RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);
lib2 = dlopen("mylib.so", RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);
我想要的是 lib1 和 lib2 有单独的地址 space 以便它们可以做不同的事情。目前,我能做到这一点的唯一方法是复制 mylib 以便代码如下所示:
lib1 = dlopen("mylib.so", RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);
lib2 = dlopen("mylib2.so", RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);
在有限的范围内,这对我来说效果很好。但是,我有一个应用程序使用库的次数一般,这使得复制库很麻烦。
是否有更好的方法让每次加载库时都有一个单独的地址space?
编辑:
我想多次加载库,因为我的应用程序正在处理一种消息队列。消息队列中的项目引用共享库的名称(例如 mylib)并包含一组应由库处理的数据。我想在多线程环境中处理 MQ,运行 每次在自己的线程中调用库的方法。
只要 MQ 仅包含一次对库的调用,一切都会按预期进行。然而,当我有两个项目使用同一个库时,事情就开始变得奇怪了。
动态加载代码的整个想法是您可以共享它,特别是与其他进程。因此,我认为不可能真正加载库两次。
虽然有一些方法可以解决这个问题。一种可能是欺骗动态链接器第二次加载它。复制库是您已经找到的一种方法。我也可以想象硬链接也可以工作。
不过,我觉得如果你按照这里的流程操作会更好。我看到有两种方法可以实现您的目标:分叉一个单独的进程或创建一个单独的 init 函数。
对于单独的进程,您只需 fork()
,在父进程和子进程之间设置适当的 IPC 机制之后,而不是再次加载库。由于 fork 创建了一个新进程,它接收自己的内存 space 并且事物保持分离。作为 IPC,我建议使用某种中间件,例如 ZeroMQ、dbus 或 XMLRPC。
另一种选择是创建一个单独的初始化函数。为此,您不是将库的状态创建为全局变量,而是将它们组合到一个结构中。然后,在该 init 函数中,您创建该结构的一个实例,设置它并 returns 它的地址。以前在全局状态上运行的所有其他函数现在接收该结构的地址作为附加(习惯上的第一个)参数。无需加载库两次,只需调用 init 函数两次即可设置单独的环境。
Is there a better way to have a separate address space for each time the library is loaded?
实际上,一个virtual address space belongs to a process(所以它里面的所有线程),不是一个共享库(它使用几个 该虚拟地址的段 space).
对于 pid 1234 的进程,使用 pmap(1) (as pmap 1234
) or proc(5)(例如尝试 cat /proc/1234/maps
...)
你真的应该避免dlopen(3)-ing the same shared library "twice" (and this is difficult, on purpose; you could use symlinks and dlopen
several symlinks to the same shared object, but you should not do this, for example because static
data would be "loaded twice" and aftermath will happen). To avoid this happening, the dynamic loader uses reference counting技巧...
另请阅读 Drepper 的 How to Write Shared Libraries
Is there a better way to have a separate address space for each time the library is loaded?
然后您需要不同的 进程,每个进程都有自己的虚拟地址space。您将使用 inter-process communication : see pipe(7), fifo(7), socket(7), unix(7), shm_overview(7), sem_overview(7) 等...
您需要使用 dlmopen 来实现这种隔离:
// No need for RTLD_LOCAL, not sure about RTLD_DEEPBIND
lib1 = dlmopen (LM_ID_NEWLM, "mylib.so", RTLD_LAZY | RTLD_DEEPBIND);
我试图在 C 中加载共享库两次:
lib1 = dlopen("mylib.so", RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);
lib2 = dlopen("mylib.so", RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);
我想要的是 lib1 和 lib2 有单独的地址 space 以便它们可以做不同的事情。目前,我能做到这一点的唯一方法是复制 mylib 以便代码如下所示:
lib1 = dlopen("mylib.so", RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);
lib2 = dlopen("mylib2.so", RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);
在有限的范围内,这对我来说效果很好。但是,我有一个应用程序使用库的次数一般,这使得复制库很麻烦。
是否有更好的方法让每次加载库时都有一个单独的地址space?
编辑:
我想多次加载库,因为我的应用程序正在处理一种消息队列。消息队列中的项目引用共享库的名称(例如 mylib)并包含一组应由库处理的数据。我想在多线程环境中处理 MQ,运行 每次在自己的线程中调用库的方法。 只要 MQ 仅包含一次对库的调用,一切都会按预期进行。然而,当我有两个项目使用同一个库时,事情就开始变得奇怪了。
动态加载代码的整个想法是您可以共享它,特别是与其他进程。因此,我认为不可能真正加载库两次。
虽然有一些方法可以解决这个问题。一种可能是欺骗动态链接器第二次加载它。复制库是您已经找到的一种方法。我也可以想象硬链接也可以工作。
不过,我觉得如果你按照这里的流程操作会更好。我看到有两种方法可以实现您的目标:分叉一个单独的进程或创建一个单独的 init 函数。
对于单独的进程,您只需 fork()
,在父进程和子进程之间设置适当的 IPC 机制之后,而不是再次加载库。由于 fork 创建了一个新进程,它接收自己的内存 space 并且事物保持分离。作为 IPC,我建议使用某种中间件,例如 ZeroMQ、dbus 或 XMLRPC。
另一种选择是创建一个单独的初始化函数。为此,您不是将库的状态创建为全局变量,而是将它们组合到一个结构中。然后,在该 init 函数中,您创建该结构的一个实例,设置它并 returns 它的地址。以前在全局状态上运行的所有其他函数现在接收该结构的地址作为附加(习惯上的第一个)参数。无需加载库两次,只需调用 init 函数两次即可设置单独的环境。
Is there a better way to have a separate address space for each time the library is loaded?
实际上,一个virtual address space belongs to a process(所以它里面的所有线程),不是一个共享库(它使用几个 该虚拟地址的段 space).
对于 pid 1234 的进程,使用 pmap(1) (as pmap 1234
) or proc(5)(例如尝试 cat /proc/1234/maps
...)
你真的应该避免dlopen(3)-ing the same shared library "twice" (and this is difficult, on purpose; you could use symlinks and dlopen
several symlinks to the same shared object, but you should not do this, for example because static
data would be "loaded twice" and aftermath will happen). To avoid this happening, the dynamic loader uses reference counting技巧...
另请阅读 Drepper 的 How to Write Shared Libraries
Is there a better way to have a separate address space for each time the library is loaded?
然后您需要不同的 进程,每个进程都有自己的虚拟地址space。您将使用 inter-process communication : see pipe(7), fifo(7), socket(7), unix(7), shm_overview(7), sem_overview(7) 等...
您需要使用 dlmopen 来实现这种隔离:
// No need for RTLD_LOCAL, not sure about RTLD_DEEPBIND
lib1 = dlmopen (LM_ID_NEWLM, "mylib.so", RTLD_LAZY | RTLD_DEEPBIND);