true singleton among shared objects - Unix

This is a discussion on true singleton among shared objects - Unix ; Hi, We are using a multithreaded application which has a few dynamic shared objects associated with it. We are running it on Linux platform. Few of the classes and code part is common among main executable and other DSOs. The ...

+ Reply to Thread
Results 1 to 7 of 7

Thread: true singleton among shared objects

  1. true singleton among shared objects

    Hi,

    We are using a multithreaded application which has a few dynamic
    shared objects associated with it. We are running it on Linux
    platform. Few of the classes and code part is common among main
    executable and other DSOs. The DSOs have been linked using linker
    option -Bsymbolic and so are able to keep their seperate objects for
    common classes.

    The issue we are having is we want to keep a true singleton of the
    common class without disturbing current linker option. For this
    purpose, we are setting an environment variable with address of object
    initialised first of all, so that once initialised same object is used
    among all DSOs.

    Please see below source code of sample application, which models my
    problem.

    // ************* LIB.H *************

    #include "string.h"
    #include
    #include
    #include

    class Common
    {
    private:
    char name[20];
    static Common *_theRegistry;
    Common()
    {
    printf ("Constructor Invoked!!\n");
    }
    public:
    static Common *InitInstance();
    static Common *GetInstance();
    char* getName();
    };


    // ************* LIB.CPP *************

    #include "lib.h"
    //#include

    const char *kENVKEY = "MYKEY";
    Common *Common::_theRegistry = NULL;
    char * Common::getName(){
    return name;
    }

    Common *Common::InitInstance()
    {
    long longEnvVal;
    char *EnvVal = getenv(kENVKEY) ;

    printf("getenv Val (%s)\n",EnvVal);

    if(EnvVal == NULL || strtol(EnvVal, NULL, 10) == -1 )
    {
    if(_theRegistry == NULL)
    {
    _theRegistry = new Common;

    char strKey[9];
    sprintf(strKey,"%0x",_theRegistry);
    char *dupenv = strdup (strKey);
    if( -1 == setenv(kENVKEY,strKey,0) )
    {
    fprintf(stderr,"Error in setenv call!!!
    \n");
    exit(1);
    }
    }
    printf("Object created (at %0x)\n ", _theRegistry);
    }
    else
    {
    longEnvVal = strtol(EnvVal, NULL, 16);
    _theRegistry = (Common *)longEnvVal;
    printf("Object found at: (%0x)\n", _theRegistry);
    }

    return _theRegistry;
    }


    Common *Common::GetInstance()
    {
    if ( _theRegistry == NULL )
    return InitInstance();
    else
    return _theRegistry;
    }

    // ************* SOFILE.CPP *************

    #include
    #include "lib.h"

    Common* pSinglton=Common::GetInstance();
    extern "C" {
    void funBeforeDlopen()
    {
    printf("Function fron library invoke before Dlopen call
    \n");
    }
    }

    // ************* MAIN.CPP *************

    #include
    #include
    #include
    #include "lib.h"


    Common* pSinglton=Common::GetInstance();
    void funMainFile(void);

    int main()
    {
    void *handle;
    char *error;
    void(*pfun)();
    printf("Blah Blah Blah of Main() now!\n");
    return 0;
    }

    And here are my g++ command

    g++ -fPIC -g -c lib.cpp
    g++ -fPIC -g -c main.cpp
    g++ -fPIC -g -c sofile.cpp

    g++ -shared -Wl,-soname,libsofile.so -o libsofile.so sofile.o lib.o -
    lc -Wl,-rpath,. -Wl,-Bsymbolic
    g++ -g -o main.exe lib.o main.o libsofile.so -L. -lsofile -Wl,-rpath,.
    -ldl

    The output of the program is as follows

    =====================
    getenv Val ((null))
    Constructor Invoked!!
    Object created (at 8d4a008)
    getenv Val ((null))
    Constructor Invoked!!
    Object created (at 8d4a0f0)
    Blah Blah Blah of Main() now!
    =====================


    Please help me undertsand why I am not able to invoke environment
    variable set by first invocation of constructor of singleton. Also
    please let me know what is the best way to solve such kind of problem.


    Any help in this regard willl be greatly appreciated.


    Thanks and Regards
    Bhawna

  2. Re: true singleton among shared objects


    >
    > =====================
    > getenv Val ((null))
    > Constructor Invoked!!
    > Object created (at 8d4a008)
    > getenv Val ((null))
    > Constructor Invoked!!
    > Object created (at 8d4a0f0)
    > Blah Blah Blah of Main() now!
    > =====================
    >
    > Please help me undertsand why I am not able to invoke environment
    > variable set by first invocation of constructor of singleton. Also
    > please let me know what is the best way to solve such kind of problem.


    In C++, initialization of static object is done by the linker: that's
    why you have the constraint that this kind of initialization can only
    be done using static functions - so the linker can find/call them.
    On UNIX systems, AFAIK, the environment is only available when
    entering main(), nothing is said regarding the availability of the
    environment before that (correct me if I am wrong please).
    So when getenv is invoked by the linker, chances are that there is no
    environment to deal with. Note that even getenv()/putenv/setenv would
    work at that point it will likely be overwritten when entering main.
    That's why you get theses null values :-)

    *** stop there if you don't want to read OT stuff ***
    You have two traces with "getenv Val ((null))\nConstructor Invoked!!".
    There is 2 calls of Common::GetInstance() in 2 different cpp unit for
    the same name pSingleton. This is a violation the one definition rule,
    and hence the program is ill-formed (the implementation and worst
    doesn't have to warn you) see standard C++ for a complete reference to
    that. So the behavior is undefined, and the implementation can do
    anything it wants.

    So if you that kind of stuff in real code, you want to fix that ;-)

    cheers,
    Paulo

  3. Re: true singleton among shared objects

    In article
    <8dd01e69-c4d0-44ea-98f1-8245a476cd93@s37g2000prg.googlegroups.com>,
    Bhawna wrote:

    > Hi,
    >
    > We are using a multithreaded application which has a few dynamic
    > shared objects associated with it. We are running it on Linux
    > platform. Few of the classes and code part is common among main
    > executable and other DSOs. The DSOs have been linked using linker
    > option -Bsymbolic and so are able to keep their seperate objects for
    > common classes.
    >
    > The issue we are having is we want to keep a true singleton of the
    > common class without disturbing current linker option. For this
    > purpose, we are setting an environment variable with address of object
    > initialised first of all, so that once initialised same object is used
    > among all DSOs.
    >
    > Please see below source code of sample application, which models my
    > problem.


    Am I confused or is this at least the third thread you've started with
    this same problem?

    --
    Barry Margolin, barmar@alum.mit.edu
    Arlington, MA
    *** PLEASE post questions in newsgroups, not directly to me ***
    *** PLEASE don't copy me on replies, I'll read them in the group ***

  4. Re: true singleton among shared objects

    On Feb 1, 6:19*am, Barry Margolin wrote:
    > In article
    > <8dd01e69-c4d0-44ea-98f1-8245a476c...@s37g2000prg.googlegroups.com>,
    >
    >
    >
    >
    >
    > *Bhawna wrote:
    > > Hi,

    >
    > > We are using a multithreaded application which has a few dynamic
    > > shared objects associated with it. We are running it on Linux
    > > platform. Few of the classes and code part is common among main
    > > executable and other DSOs. The DSOs have been linked using linker
    > > option -Bsymbolic and so are able to keep their seperate objects for
    > > common classes.

    >
    > > The issue we are having is we want to keep a true singleton of the
    > > common class without disturbing current linker option. For this
    > > purpose, we are setting an environment variable with address of object
    > > initialised first of all, so that once initialised same object is used
    > > among all DSOs.

    >
    > > Please see below source code of sample application, which models my
    > > problem.

    >
    > Am I confused or is this at least the third thread you've started with
    > this same problem?
    >
    > --
    > Barry Margolin, bar...@alum.mit.edu
    > Arlington, MA
    > *** PLEASE post questions in newsgroups, not directly to me ***
    > *** PLEASE don't copy me on replies, I'll read them in the group ***- Hidequoted text -
    >
    > - Show quoted text -


    No, there is no thread started and rather even main has not started
    before all this happens. This is exactly as Paulo has suggested and
    the reason he explains is what I had suspected.

    Also as an answer to Paulo's suspicion for 2 pSingletons, that is not
    a problem as we are using Bsybolic linker option which will eventually
    create SO speciifc variable and so that is not a problem.

    Thanks and Regards
    Bhawna

  5. Re: true singleton among shared objects

    On Jan 31, 4:05*pm, Bhawna wrote:
    > Hi,
    >
    > We are using a multithreaded application which has a few dynamic
    > shared objects associated with it. We are running it on Linux
    > platform. Few of the classes and code part is common among main
    > executable and other DSOs. The DSOs have been linked using linker
    > option -Bsymbolicand so are able to keep their seperate objects for
    > common classes.
    >
    > The issue we are having is we want to keep a true singleton of the
    > common class without disturbing current linker option. For this
    > purpose, we are setting an environment variable with address of object
    > initialised first of all, so that once initialised same object is used
    > among all DSOs.
    >
    > Please see below source code of sample application, which models my
    > problem.
    >
    > // ************* LIB.H *************
    >
    > #include "string.h"
    > #include
    > #include
    > #include
    >
    > class Common
    > {
    > * * * * private:
    > * * * * * * * * char name[20];
    > * * * * * * * * static Common *_theRegistry;
    > * * * * * * * * Common()
    > * * * * * * * * {
    > * * * * * * * * * * * * printf ("Constructor Invoked!!\n");
    > * * * * * * * * }
    > * * * * public:
    > * * * * * * * * static Common *InitInstance();
    > * * * * * * * * static Common *GetInstance();
    > * * * * * * * * char* getName();
    >
    > };
    >
    > // ************* LIB.CPP *************
    >
    > #include "lib.h"
    > //#include
    >
    > const char *kENVKEY = "MYKEY";
    > Common *Common::_theRegistry = NULL;
    > char * Common::getName(){
    > * * * * return name;
    >
    > }
    >
    > Common *Common::InitInstance()
    > {
    > * * * * long longEnvVal;
    > * * * * char *EnvVal = getenv(kENVKEY) ;
    >
    > * * * * printf("getenv Val (%s)\n",EnvVal);
    >
    > * * * * if(EnvVal == *NULL || strtol(EnvVal, NULL, 10) == -1 )
    > * * * * {
    > * * * * * * * * if(_theRegistry == NULL)
    > * * * * * * * * {
    > * * * * * * * * * * * * _theRegistry = new Common;
    >
    > * * * * * * * * * * * * char strKey[9];
    > * * * * * * * * * * * * sprintf(strKey,"%0x",_theRegistry);
    > * * * * * * * * * * * * char *dupenv = strdup (strKey);
    > * * * * * * * * * * * * if( -1 == setenv(kENVKEY,strKey,0) )
    > * * * * * * * * * * * * {
    > * * * * * * * * * * * * * * * * fprintf(stderr,"Error in setenv call!!!
    > \n");
    > * * * * * * * * * * * * * * * * exit(1);
    > * * * * * * * * * * * * }
    > * * * * * * * * }
    > * * * * * * * * printf("Object created (at %0x)\n ", _theRegistry);
    > * * * * }
    > * * * * else
    > * * * * {
    > * * * * * * * * longEnvVal = strtol(EnvVal, NULL, 16);
    > * * * * * * * * _theRegistry = (Common *)longEnvVal;
    > * * * * * * * * printf("Object found at: (%0x)\n", _theRegistry);
    > * * * * }
    >
    > * * * * return _theRegistry;
    >
    > }
    >
    > Common *Common::GetInstance()
    > {
    > * * * * if ( _theRegistry == NULL )
    > * * * * * * * * return InitInstance();
    > * * * * else
    > * * * * * * * * return _theRegistry;
    >
    > }
    >
    > // ************* SOFILE.CPP *************
    >
    > #include
    > #include "lib.h"
    >
    > Common* pSinglton=Common::GetInstance();
    > extern "C" {
    > * * * * void funBeforeDlopen()
    > * * * * {
    > * * * * * * * * printf("Function fron library invoke before Dlopen call
    > \n");
    > * * * * }
    >
    > }
    >
    > // ************* MAIN.CPP *************
    >
    > #include
    > #include
    > #include
    > #include "lib.h"
    >
    > Common* pSinglton=Common::GetInstance();
    > void funMainFile(void);
    >
    > int main()
    > {
    > * * * * void *handle;
    > * * * * char *error;
    > * * * * void(*pfun)();
    > * * * * printf("Blah Blah Blah of Main() now!\n");
    > * * * * return 0;
    >
    > }
    >
    > And here are my g++ command
    >
    > g++ -fPIC -g -c lib.cpp
    > g++ -fPIC -g -c main.cpp
    > g++ -fPIC -g -c sofile.cpp
    >
    > g++ -shared -Wl,-soname,libsofile.so -o libsofile.so sofile.o lib.o -
    > lc -Wl,-rpath,. -Wl,-Bsymbolic
    > g++ -g -o main.exe lib.o main.o libsofile.so -L. -lsofile -Wl,-rpath,.
    > -ldl
    >
    > The output of the program is as follows
    >
    > =====================
    > getenv Val ((null))
    > Constructor Invoked!!
    > Object created (at 8d4a008)
    > *getenv Val ((null))
    > Constructor Invoked!!
    > Object created (at 8d4a0f0)
    > *Blah Blah Blah of Main() now!
    > =====================
    >
    > Please help me undertsand why I am *not able to invoke environment
    > variable set by first invocation of constructor of singleton. Also
    > please let me know what is the best way to solve such kind of problem.
    >
    > Any help in this regard willl be greatly appreciated.
    >
    > Thanks and Regards
    > Bhawna


    Hi Paulo or group members,

    Did you get a chance to look at my previous reply. One updates here is
    I am able to achieve the output I want on Solaris platform but not on
    Linux (RHEL 3 and 4).
    If anyone could suggest any workaround to resolvee few symbols
    externally inspite of using -Bsymbolic, than it would be a great help.

    Thanks and Regards
    Bhawna

  6. Re: true singleton among shared objects

    > Did you get a chance to look at my previous reply. One updates here is
    > I am able to achieve the output I want on Solaris platform but not on
    > Linux (RHEL 3 and 4).
    > If anyone could suggest any workaround to resolvee few symbols
    > externally inspite of using -Bsymbolic, than it would be a great help.


    Here is how I would do it:
    remove the static inititialization Common*
    pSinglton=Common::GetInstance() and replace it with NULL.

    use the pthread_once_t / pthread_once() duet - its from the Unix spec.
    3 is "pthread_once - dynamic package initialisation" which is what you
    may want to achieve :-)

    // wrapper so we don not change the signature of InitInstance()
    // and we keep the compiler happy by returning void
    void wrapper()
    {
    Common::InitInstance();
    }

    // per process
    static pthread_once_t singleton_is_initialized = PTHREAD_ONCE_INIT;

    Common *Common::GetInstance()
    {
    if ( _theRegistry == NULL )
    {
    int rc = pthread_once(&singleton_is_initialized,
    wrapper);
    // proper error handling from here
    }

    // still null ???
    if ( _theRegistry == NULL )
    {
    // should not happen
    // if it does :-) we ran into a caching issue. Try to
    declare
    // _theRegistry as volatile so the compiler do not play
    any
    // tricks behind your back. and then do the proper casting
    when
    // returning from this function (use const_cast to cast
    away
    // volatile).
    abort();
    }

    return _theRegistry;
    }

    check (and if needed register) the signle unix spec 3 from the
    opengroup.

    cheers,
    Paulo

  7. Re: true singleton among shared objects

    On Feb 5, 8:13*pm, ppi wrote:
    > > Did you get a chance to look at my previous reply. One updates here is
    > > I am able to achieve the output I want on Solaris platform but not on
    > > Linux (RHEL 3 and 4).
    > > If anyone could suggest any workaround to resolvee few symbols
    > > externally inspite of using -Bsymbolic, than it would be a great help.

    >
    > Here is how I would do it:
    > remove the static inititialization Common*
    > pSinglton=Common::GetInstance() and replace it with NULL.
    >
    > use the pthread_once_t / pthread_once() duet - its from the Unix spec.
    > 3 is "pthread_once - dynamic package initialisation" which is what you
    > may want to achieve :-)
    >
    > // wrapper so we don not change the signature of InitInstance()
    > // and we keep the compiler happy by returning void
    > void wrapper()
    > {
    > * * Common::InitInstance();
    >
    > }
    >
    > // per process
    > static pthread_once_t singleton_is_initialized = PTHREAD_ONCE_INIT;
    >
    > Common *Common::GetInstance()
    > {
    > * * * * if ( _theRegistry == NULL )
    > * * * * {
    > * * * * * * * *int rc = pthread_once(&singleton_is_initialized,
    > wrapper);
    > * * * * * * * *// proper error handling from here
    > * * * * }
    >
    > * * * * // still null ???
    > * * * * if ( _theRegistry == NULL )
    > * * * * {
    > * * * * * * // should not happen
    > * * * * * * // if it does :-) we ran into a caching issue. Tryto
    > declare
    > * * * * * * // _theRegistry as volatile so the compiler do notplay
    > any
    > * * * * * * // tricks behind your back. and then do the propercasting
    > when
    > * * * * * * // returning from this function (use const_cast tocast
    > away
    > * * * * * * // volatile).
    > * * * * * * abort();
    > * * * * }
    >
    > * * * * return _theRegistry;
    >
    > }
    >
    > check (and if needed register) the signle unix spec 3 from the
    > opengroup.
    >
    > cheers,
    > Paulo


    Hi Paulo,

    Thank you very much for your prompt response. Before I register the
    single spec 3 from the opengroup, I wanted to clear few doubts. Even
    after multiple inclusion of common class will I be able to keep
    *static pthread_once_t singleton_is_initialized* within the process.
    Based on what I understand from Man pages I am reading the answer to
    this question seems to be Yes.

    But then it solves part of my problem that InitInstance is called only
    once. But the complete solution would be to get the address of object
    created by that single call, and spread it across various shared
    objects.

    Also I could not understand one part of your response where you have
    suggested to replace static initialization with NULL. Had I have the
    choice to do so, I would not have any problem at all, because once the
    main starts I have control over environment and problem can be solved
    using environment being set with the value that is needed to be spread
    across various shared objects.

    Thanks and Regards
    Bhawna


+ Reply to Thread