What would cause multiple instances of singleton in DLL?

157 views Asked by At

I am aware that this question has been asked and answered in different forms over the years, but I find the previous Q&As about it too tied to specific examples and not providing me with a full understanding of why, and in what scenarios, dlls can produce multiple instances of the same singleton. I am struggling to come up with a minimal reproducible example myself.

Given a singleton in the rough form:

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;
}

This is compiled in to a dll (I'll call is SingletonAndOtherStuff.dll) which is intended for loading via LoadLibrary by other apps.

This next bit is where I start to get confused.

Within a separate primary app (I'll call it app.exe), SingletonAndOtherStuff.dll is loaded via LoadLibrary in two places. What situations could cause multiple copies of the static variable m_instance to appear?

  • In the case of diamond pattern, would this lead to two of the singleton?:
             app.exe
            /       \
static/shared_lib static/shared_lib
            \       /
    SingletonAndOtherStuff.dll
  • If I had multiple copies of the exact same dll on disk, would that lead to multiple copies of the singleton?
                      app.exe
                     /       \
                    /         \
        static/shared_lib static/shared_lib
                 |                 |
SingletonAndOtherStuff.dll SingletonAndOtherStuff.dll
  • If there were other combinations or longer chains of STATIC and SHARED libraries between app.exe and SingletonAndOtherStuff.dll, could that cause multiple instances of the singleton?

I am just looking for an explanation for what would cause this pattern to fall over in the situation where the dll is loaded twice.

1

There are 1 answers

0
santranti On BEST ANSWER

Okay, let's break this down piece by piece. This dilemma you're facing is quite common among developers when dealing with shared libraries, and the presence of singletons just adds another layer of complexity. Thanks for giving a detailed context; I'll tackle each segment.

  1. Singleton Inside a DLL:

First off, our singleton pointer, being static, has its place reserved in memory as soon as our DLL is loaded. This space remains unique, ensuring our singleton stays singular if the DLL is only loaded once.

  1. What Happens When a DLL is Loaded More Than Once?:

Here's the thing: even if you repeatedly call LoadLibrary for the same DLL within the same process, the OS doesn't load it afresh each time. It's smart about it and just ups its internal reference count. This ensures our singleton isn't cloned.

  1. About That Diamond Pattern:

The pattern you've mapped out:

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

Even if both those static/shared libraries beckon the SingletonAndOtherStuff.dll, it remains one and the same in memory. So, our buddy singleton stays one of a kind.

  1. Dealing With Twin DLLs on Disk:

Now, consider this setup:

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

If you've got two identical DLLs, but they're sitting at different addresses on your disk and both get loaded, the OS sees them as distinct entities. This means they each get their own spot in memory, causing our singleton to be replicated. Yes, you'd end up with two singletons.

  1. Tangled Webs of Libraries:

It doesn't matter how convoluted the library chain gets. The key thing? How many times, and from which spots on your disk, the SingletonAndOtherStuff.dll gets loaded. Different locations mean different singleton instances.

To wrap up: the singleton behaves as expected when our DLL is invited once from a single spot within one process. But if you're pulling in the same DLL from multiple addresses, even if they're carbon copies, you'll get multiple singletons. It's a quirky aspect of shared libraries, and it's essential to have a grasp on these dynamics when diving into such waters.