提问人:Cascades 提问时间:10/8/2023 更新时间:10/8/2023 访问量:87
什么会导致DLL中出现多个单例实例?
What would cause multiple instances of singleton in DLL?
问:
我知道这个问题多年来以不同的形式被提出和回答,但我发现之前关于它的问答过于与具体示例联系在一起,并没有让我完全理解为什么以及在什么情况下,dll可以产生同一个单例的多个实例。我自己正在努力想出一个最小的可重复的例子。
给定一个粗略形式的单例:
class Singleton
{
private:
static Singleton* singleton;
public:
Singelton(); //
~Singleton(); // Not shown for brevity.
static Singelton* getSingleton();
};
Singleton* Singleton::getSingleton()
{
if (!singleton)
{
singleton= new Singleton;
}
return singleton;
}
它被编译成一个dll(我称之为是),该dll旨在由其他应用程序加载。SingletonAndOtherStuff.dll
LoadLibrary
接下来是我开始感到困惑的地方。
在一个单独的主应用程序(我称之为)中,通过在两个地方加载。什么情况会导致出现静态变量的多个副本?app.exe
SingletonAndOtherStuff.dll
LoadLibrary
m_instance
- 在菱形图案的情况下,这是否会导致两个单例?
app.exe
/ \
static/shared_lib static/shared_lib
\ /
SingletonAndOtherStuff.dll
- 如果我在磁盘上有完全相同的 dll 的多个副本,这是否会导致单例的多个副本?
app.exe
/ \
/ \
static/shared_lib static/shared_lib
| |
SingletonAndOtherStuff.dll SingletonAndOtherStuff.dll
- 如果 和 之间有其他组合或更长的 and 库链,这会导致单例的多个实例吗?
STATIC
SHARED
app.exe
SingletonAndOtherStuff.dll
我只是在寻找一个解释,说明在dll加载两次的情况下,什么会导致这种模式失败。
答:
好吧,让我们一点一点地分解一下。在处理共享库时,您面临的这种困境在开发人员中很常见,而单例的存在只会增加另一层复杂性。感谢您提供详细的背景信息;我将处理每个部分。
- DLL 中的单例:
首先,我们的单例指针是静态的,一旦加载 DLL,它就会在内存中保留它的位置。此空间保持唯一,确保在仅加载一次 DLL 时,我们的单例保持单一。
- 当 DLL 加载多次时会发生什么情况?
事情是这样的:即使在同一进程中为同一 DLL 重复调用 LoadLibrary,操作系统也不会每次都重新加载它。它很聪明,只是增加了它的内部引用数量。这样可以确保我们的单例不会被克隆。
- 关于那个钻石图案:
您绘制的模式:
app.exe
/ \
static/shared_lib static/shared_lib
\ /
SingletonAndOtherStuff.dll
即使这两个静态/共享库都在召唤,它在内存中仍然是相同的。所以,我们的伙伴是独一无二的。SingletonAndOtherStuff.dll
singleton
- 处理磁盘上的双 DLL:
现在,请考虑以下设置:
app.exe
/ \
/ \
static/shared_lib static/shared_lib
| |
SingletonAndOtherStuff.dll SingletonAndOtherStuff.dll
如果有两个相同的 DLL,但它们位于磁盘上的不同地址,并且都已加载,则操作系统会将它们视为不同的实体。这意味着他们每个人都在记忆中占有自己的位置,导致我们的被复制。是的,你最终会得到两个单例。singleton
- 错综复杂的图书馆网络:
图书馆链变得多么复杂并不重要。关键是什么?加载了多少次,以及从磁盘上的哪些位置加载。不同的位置意味着不同的单例实例。SingletonAndOtherStuff.dll
总结一下:当我们的 DLL 从一个进程中的单个位置被邀请一次时,单例的行为符合预期。但是,如果从多个地址拉取相同的 DLL,即使它们是副本,也会得到多个单一实例。这是共享图书馆的一个古怪方面,在潜入此类水域时,掌握这些动态至关重要。
评论
SingletonAndOtherStuff.dll