什么会导致DLL中存在多个单例实例?

问题描述 投票:0回答:1

我知道多年来这个问题已经以不同的形式被提出和回答,但我发现之前的问答与具体的例子过于相关,并没有让我充分理解为什么以及在什么情况下,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 中(我称之为

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
  • 如果
    STATIC
    SHARED
    之间存在其他组合或更长的
    app.exe
    SingletonAndOtherStuff.dll
    库链,是否会导致单例的多个实例?

我只是在寻找一个解释,解释在 dll 加载两次的情况下,什么会导致此模式失败。

c++ visual-c++ dll loadlibrary cl
1个回答
0
投票

好吧,让我们一点一点地分解。在处理共享库时,您面临的这种困境在开发人员中很常见,而单例的存在只会增加另一层复杂性。感谢您提供详细的背景信息;我会处理每个部分。

  1. DLL 内的单例:

首先,我们的单例指针是静态的,一旦我们的 DLL 被加载,它的位置就被保留在内存中。这个空间保持唯一,确保我们的单例在 DLL 仅加载一次时保持单一。

  1. 多次加载 DLL 时会发生什么?:

事情是这样的:即使您在同一个进程中重复调用同一个 DLL 的 LoadLibrary,操作系统也不会每次都重新加载它。它很聪明,只是增加了其内部引用计数。这确保了我们的单例不会被克隆。

  1. 关于钻石图案:

你已经绘制出的模式:

             app.exe
            /       \
static/shared_lib static/shared_lib
            \       /
    SingletonAndOtherStuff.dll

即使这两个静态/共享库都召唤了

SingletonAndOtherStuff.dll
,它在内存中仍然保持不变。所以,我们的伙伴
singleton
仍然是独一无二的。

  1. 处理磁盘上的双DLL

现在,考虑这个设置:

                  app.exe
                 /       \
                /         \
    static/shared_lib static/shared_lib
             |                 |
SingletonAndOtherStuff.dll SingletonAndOtherStuff.dll

如果您有两个相同的 DLL,但它们位于磁盘上的不同地址并且都被加载,则操作系统将它们视为不同的实体。这意味着它们各自在内存中拥有自己的位置,从而导致我们的

singleton
被复制。是的,你最终会得到两个单身人士。

  1. 错综复杂的图书馆网

图书馆链变得多么复杂并不重要。关键是什么?

SingletonAndOtherStuff.dll
被加载多少次,从磁盘上的哪些位置加载。不同的位置意味着不同的单例实例。

总结一下:当我们的 DLL 从一个进程内的单个位置被邀请一次时,单例会按预期运行。但是,如果您从多个地址提取同一个 DLL,即使它们是副本,您也会获得多个单例。这是共享库的一个奇怪的方面,在进入这样的领域时掌握这些动态至关重要。

© www.soinside.com 2019 - 2024. All rights reserved.