我有一个库(L),它由程序(P)使用dlopen动态加载。 L实现了一个插件接口,因此回调它的父节点以获得一些功能。
Inside P是一个动态创建线程池对象A的单例对象。 我需要从L获得A。
然而,因为单例通过使用静态变量来工作,所以当加载L时,它最终会创建它自己的实例,这在某些情况下会很好但是我想要在P中创建的实例。有没有办法绕过这个?
答案 0 :(得分:1)
你不应该在L中有static
A.让P将A的地址传递给L,即L.init(&A)
。
答案 1 :(得分:1)
声明为static
的文件范围名称具有内部链接。内部链接意味着它们对其他翻译单元是不可见的,即使在没有任何动态库的“经典”链接模型中也是如此。鉴于即使对于同一可执行文件中的其他翻译单元也看不到静态,因此期望从附加的动态库中看到它们是不合理的。
您必须考虑使用外部动态符号实现必要链接的方法。也许单身人士根本不能拥有内部名称,但必须有外部名称。
L正在创建自己的对象实例,不仅因为该对象是静态的,而且因为您已将链接到L的线程池模块定义了该单例和线程池函数。即使对象具有外部名称,也会发生这种情况,具体取决于库的链接方式。
您必须选择线程池服务所在的单个对象,然后确保它只驻留在那里。你的项目是不是有一个实用程序库,你可以坚持这种事情?
你可以遵守提供线程池API的程序可执行文件P的模型。这真是一回事。程序P是另一个动态对象,有效地充当线程池模块的库,它提供给自己和其他共享对象。
无论该线程池模块的位置如何,请确保您没有将该模块的副本静态链接到其他对象:它只存在于一个位置。
如果线程池单例的外部名称是该API的一部分(每个人都知道它的文档名称并直接使用它,将该全局池传递给API函数),那么该名称应该是外部的,并在头文件中声明。
如果单例是私有的,那么你必须考虑一些隐藏它的方法,比如在函数调用中隐含它(只有一个线程池,那就是那个)或者抽象访问它有点(提供ensure_thread_pool
)函数,如果一个线程池不存在,它会创建一个线程池,或者以线程安全的方式返回先前创建的线程池。
想一想:为什么不这样做,例如,stdin
和stdout
有这个问题?为什么不是每个库都实例化自己的stdout
流并在该流上调用自己的fprintf
函数?显然,为什么这些东西生活在一个地方:C库。他们的副本不住在其他地方;其他地方只需通过动态符号引用它们。