Thread: global and static variable in a class delivered in a DLL

  1. #1
    Registered User
    Join Date
    May 2006
    Posts
    1,579

    global and static variable in a class delivered in a DLL

    Hello everyone,


    If we define global variable and static variable of a class, which are implemented in a DLL. My questions are,

    1. All instances of class share the single copy of global variable and static variable of class? If yes, I need to have some synchronization approach on them.

    2. Is it safe to use global variable and static (public) variable after DLL unloads?


    thanks in advance,
    George

  2. #2
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    1. Yes - but only within the same process. Synchronize if it's needed.
    2. No - once dll unloads, it's gone

    gg

  3. #3
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks gg,


    Is it possible a DLL is load multiple times by the same process? If possible, a process may have multiple copies of global/static data of a DLL?

    Quote Originally Posted by Codeplug View Post
    1. Yes - but only within the same process. Synchronize if it's needed.
    2. No - once dll unloads, it's gone

    gg

    regards,
    George

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I suppose it might be possible, but not with any conventional means. Trying to load the same dll twice using LoadLibrary will only increment the dll load count (thus requiring two free calls before it's unloaded).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks Elysia,


    You mean even if DLL is loaded multiple times, the global and static data in the DLL share only one copy?

    Quote Originally Posted by Elysia View Post
    I suppose it might be possible, but not with any conventional means. Trying to load the same dll twice using LoadLibrary will only increment the dll load count (thus requiring two free calls before it's unloaded).

    regards,
    George

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Yes, since the dll is only mapped once into the process space.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks Elysia,


    Question answered.

    Quote Originally Posted by Elysia View Post
    Yes, since the dll is only mapped once into the process space.

    regards,
    George

  8. #8
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    It is highly possible to end up with two different statics. One in the DLL and one in the main module.

    For instance if you have a singleton and a DLL needs access to it you very well will end up with two distinct instances of the singleton. One in your DLL and one in the main module. I just encountered this the other day at work and it is quite annoying. If the static is only in the DLL then you will not have any issues. But if this is a shared static in that it crosses DLL or module boundaries you will have issues.

    If a singleton is instantiated outside of the DLL and the DLL then calls getInstance() to use the singleton, the DLL will have a completely new instance of the singleton. Nothing you do can protect against this since it is a caveat of DLLs.

  9. #9
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    I'm not following you Bubba - can you give a code example? I don't see it.

    gg

  10. #10
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    The problem is that DLLs have their own local heap for static variables. This can cause serious issues. In most cases this is not a concern but there are a few edge cases that will bite you. If you have a singleton in DLL A and a singleton in DLL B and then you try to use A from B you will have problems.

    Singleton A - DLL 1
    Singleton B - DLL 2

    MainModule
    ---------------
    1. Creates A
    2. Creates B

    DLL 2
    -------
    1. Tries to use A.
    2. Will get a different instance of A than what is in the main module.
    Last edited by VirtualAce; 04-12-2008 at 07:46 AM.

  11. #11
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> The problem is that DLLs have their own local heap for static variables.
    Sorry - I still don't understand. Can you modify this code to demonstrate an "edge case"?

    DLL 1:
    Code:
    #include <windows.h>
    #include <iostream>
    using namespace std;
    
    int g_obj1;
    
    extern "C" __declspec(dllexport) 
    void* GetSingleton1() 
    {
        return &g_obj1;
    }//GetSingleton1
    
    extern "C" __declspec(dllexport) 
    void ReportInstances1()
    {
        HMODULE hmod = LoadLibraryA("DLL2.dll");
        if (!hmod)
        {
            cout << "DLL1: LoadLibrary() failed, ec = " << GetLastError() << endl;
            return;
        }//if
        
        typedef void* (*GetSingleton2_pfn)();
        GetSingleton2_pfn GetSingleton2 = (GetSingleton2_pfn)GetProcAddress(hmod, "GetSingleton2");
        if (!GetSingleton2)
        {
            cout << "DLL1: GetProcAddress() failed, ec = " << GetLastError() << endl;
            FreeLibrary(hmod);
            return;
        }//if
    
        cout << "DLL1: instance 1 at " << reinterpret_cast<long>(GetSingleton1()) << endl;
        cout << "DLL1: instance 2 at " << reinterpret_cast<long>(GetSingleton2()) << endl;
        
        FreeLibrary(hmod);
    }//ReportInstances1
    
    __declspec(dllexport)
    BOOL WINAPI DllMain(HINSTANCE hInst, DWORD Reason, LPVOID Reserved)
    {
        return TRUE;
    }//DllMain
    DLL 2:
    Code:
    #include <windows.h>
    #include <iostream>
    using namespace std;
    
    int g_obj2;
    
    extern "C" __declspec(dllexport) 
    void* GetSingleton2() 
    {
        return &g_obj2;
    }//GetSingleton2
    
    extern "C" __declspec(dllexport) 
    void ReportInstances2()
    {
        HMODULE hmod = LoadLibraryA("DLL1.dll");
        if (!hmod)
        {
            cout << "DLL2: LoadLibrary() failed, ec = " << GetLastError() << endl;
            return;
        }//if
        
        typedef void* (*GetSingleton1_pfn)();
        GetSingleton1_pfn GetSingleton1 = (GetSingleton1_pfn)GetProcAddress(hmod, "GetSingleton1");
        if (!GetSingleton1)
        {
            cout << "DLL2: GetProcAddress() failed, ec = " << GetLastError() << endl;
            FreeLibrary(hmod);
            return;
        }//if
    
        cout << "DLL2: instance 1 at " << reinterpret_cast<long>(GetSingleton1()) << endl;
        cout << "DLL2: instance 2 at " << reinterpret_cast<long>(GetSingleton2()) << endl;
        
        FreeLibrary(hmod);
    }//ReportInstances2
    
    __declspec(dllexport)
    BOOL WINAPI DllMain(HINSTANCE hInst, DWORD Reason, LPVOID Reserved)
    {
        return TRUE;
    }//DllMain
    Main:
    Code:
    #include <windows.h>
    #include <iostream>
    using namespace std;
    
    #pragma comment(lib, "DLL1.lib")
    #pragma comment(lib, "DLL2.lib")
    
    extern "C" __declspec(dllimport) void* GetSingleton1(); 
    extern "C" __declspec(dllimport) void* GetSingleton2();
    extern "C" __declspec(dllimport) void ReportInstances1();
    extern "C" __declspec(dllimport) void ReportInstances2();
    
    int main()
    {
        cout << "MAIN: instance 1 at " << reinterpret_cast<long>(GetSingleton1()) << endl;
        cout << "MAIN: instance 2 at " << reinterpret_cast<long>(GetSingleton2()) << endl;
        ReportInstances1();
        ReportInstances2();
    
        return 0;
    }//main
    Output:
    Code:
    MAIN: instance 1 at 3421008
    MAIN: instance 2 at 268448592
    DLL1: instance 1 at 3421008
    DLL1: instance 2 at 268448592
    DLL2: instance 1 at 3421008
    DLL2: instance 2 at 268448592
    gg

  12. #12
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Well first of all that is not what I would consider a Singleton and def not C++. Create a class pattern for a singleton and use that in 2 sep dlls.

    Code:
    class A
    {
       public:
         static A* getInstance()
         {
             if (m_pInstance)
            {
                m_pInstance = new A;
            }
            return m_pInstance;
         }
    
         void DoSomething() { }
    
       private:
           A() { }
           A(const A& obj);
           A& operator = (const A& obj);
    
           static A* m_pInstance;
     };
    Code:
    class B
    {
       public:
         static B* getInstance()
         {
             if (m_pInstance)
            {
                m_pInstance = new B;
            }
            return m_pInstance;
         }
    
         void DoSomething() { }
    
       private:
           B() { }
           B(const B& obj);
           B& operator = (const B& obj);
    
           static B* m_pInstance;
    };
    Using this pattern if you now instantiate A and B from the main module you will have a single instance of A and B. However let's say that the DLL in which B resides now needs an instance of A to perform some operation.

    Code:
    A::getInstance()->DoSomething();
    All that needs to be added is a #define to use dllexport or dllimport and these singletons should be ready to place into a DLL.
    Last edited by VirtualAce; 04-12-2008 at 11:01 AM.

  13. #13
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> static A* m_pInstance;
    This is just a global variable just like my "int g_obj1". Wrapping it in a class makes no difference.

    There is only 1 copy if a DLL's global/static data per process.

    What you're describing is when two modules link to the same static library with globals - in which case both modules will get their own copy of the static lib's globals.

    It can be fairly easy to be "bitten" by this. Let's say your class A and class B are in AB.cpp. Then both DLL1 and DLL2 compiles and links in AB.cpp. Now both DLL's have their own copy of the "globals" in AB.cpp - A::m_pInstance and B::m_pInstance. If you only want one instance per process, then only one module should compile/link/expose AB.cpp

    gg

  14. #14
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    This is just a global variable just like my "int g_obj1". Wrapping it in a class makes no difference.
    Technically, you are right. But this is the C++ board and in general the term Singleton refers to a specific class pattern or anti-pattern depending on how you feel about singleton's in general.

    The DLL's held the singletons and the main module instantiated them. The static instances were in the DLLs. However A needed B and B needed A which caused the problem. Because of this B.cpp had to be in A's project and vice versa. So in essence we are saying about the same thing just in different ways. But there are definite ways to end up with two instances even when using singletons when it comes to DLLs. That was the jist of my point and I think it's not only been made but proven. It depends on how you are using the DLLs and the statics that determines if you have success or failure. We both have shown ways that this can fail.
    Last edited by VirtualAce; 04-13-2008 at 12:30 AM.

  15. #15
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    I just want to avoid any confusion by readers....

    The OS will only load 1 copy of a modules globals per process. If you the programmer link the same globals into multiple modules - that's your doing

    gg

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Static Local Variable vs. Global Variable
    By arpsmack in forum C Programming
    Replies: 7
    Last Post: 08-21-2008, 03:35 AM
  2. LNK2001 ERROR!!! need help
    By lifeafterdeath in forum C++ Programming
    Replies: 7
    Last Post: 05-27-2008, 05:05 PM
  3. static class variable vs. global variable
    By nadamson6 in forum C++ Programming
    Replies: 18
    Last Post: 09-30-2005, 03:31 PM
  4. Replies: 2
    Last Post: 10-02-2004, 10:12 AM
  5. Static global variable acting as global variable?
    By Visu in forum C Programming
    Replies: 2
    Last Post: 07-20-2004, 08:46 AM