如何从 dlopen'd 库 L 访问程序 P 中的静态变量?

How can I accessing a static variable in program P from dlopen'd library L?

本文关键字:程序 访问 变量 静态 dlopen      更新时间:2023-10-16

我有一个库(L),它是由程序(p)使用dlopen动态加载的。L实现了一个插件接口,因此调用它的父接口以获得一些功能。

在p内部是一个单例对象,它动态地创建一个线程池对象a。我需要从L.访问A

然而,因为singleton是通过使用静态变量来工作的,所以当加载L时,它最终会创建自己的实例,在某些情况下这是可以的,但我想要在p中创建的实例。有办法解决这个问题吗?

L中不应该有static a。让p将a的地址传递给L,即L.init(&A)

声明为static的文件作用域名称具有内部链接。内部链接意味着它们对其他翻译单元是不可见的,即使在没有任何动态库的"经典"链接模型中也是如此。假设静态即使对同一可执行文件中的其他翻译单元也不可见,那么期望它们从附加的动态库中可见是不合理的。

你必须想办法使用外部的、动态的符号来实现必要的联系。也许单例不能有内部名称,而必须有外部名称。

L正在创建自己的对象实例,这不仅是因为对象是静态的,还因为您已经将定义该单例和线程池函数的线程池模块链接到L中。即使是具有外部名称的对象也可能发生这种情况,具体取决于库的链接方式。

您必须选择线程池服务将驻留在其中的单个对象,然后确保它只驻留在其中。你的项目不是有一个实用程序库,你可以在那里坚持这种东西吗?

可以遵循这样的模型,即它是提供线程池API的程序可执行程序p。这真的是一样的事情。程序P是另一个动态对象,有效地充当线程池模块的库,它将线程池模块提供给自己和其他共享对象。

无论线程池模块位于何处,都要确保没有将该模块的副本静态链接到其他对象:它只位于一个位置。

如果线程池单例的外部名称是该API的一部分(每个人都知道其文档化名称,并直接使用它,将该全局池传递给API函数),则该名称应为外部名称,并在头文件中声明。

如果单例是私有的,那么你必须考虑一些隐藏它的方法,比如让它隐含在函数调用中(只有一个线程池,也就是说),或者在某种程度上抽象对它的访问(提供一个ensure_thread_pool)函数,该函数在线程池不存在的情况下创建线程池,或者以线程安全的方式返回以前创建的线程池。

思考:为什么stdinstdout没有这个问题?为什么每个库都不实例化自己的stdout流,并在该流上调用自己的fprintf函数?为什么,很明显,因为这些东西存在于一个地方:C库。它们的副本不存在于其他地方;其他地方只是通过动态符号引用它们。