Writing Singleton Classes

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • cppaddict

    Writing Singleton Classes

    Hi,

    In this tutorial on singleton class in C++
    (http://gethelp.devx.com/techtips/cpp.../10min0200.asp) the
    author gives two implementations of a simple singleton class, claiming
    that only the first is safe for multi-threaded appliactions. I want
    to know why this so.

    The class is as follows:

    class Singleton
    {
    public:
    static Singleton* Instance();
    protected:
    Singleton();
    Singleton(const Singleton&);
    Singleton& operator= (const Singleton&);
    private:
    static Singleton* pinstance;
    };

    The first implementation is:

    Singleton* Singleton::pins tance = 0;// initialize pointer
    Singleton* Singleton::Inst ance ()
    {
    if (pinstance == 0) // is it the first call?
    {
    pinstance = new Singleton; // create sole instance
    }
    return pinstance; // address of sole instance
    }
    Singleton::Sing leton()
    {
    //... perform necessary instance initializations
    }

    The second implementation makes a small change to the constructor:

    Singleton* Singleton::Inst ance ()
    {
    static Singleton inst;
    return &inst;
    }

    The author notes that the second implementation is optimized for
    single-threaded applications. Why would it not also work for
    multi-threaded applications?

    Thanks,
    cpp

  • Benoit Mathieu

    #2
    Re: Writing Singleton Classes

    cppaddict wrote:[color=blue]
    > Hi,
    >
    > In this tutorial on singleton class in C++
    > (http://gethelp.devx.com/techtips/cpp.../10min0200.asp) the
    > author gives two implementations of a simple singleton class, claiming
    > that only the first is safe for multi-threaded appliactions. I want
    > to know why this so.
    > ...[/color]

    I found an answer here :


    Now, the first implementation is also problematic, and has
    exactely the same problem: initialisation must be protected
    by a mutex or something...

    Benoit

    Comment

    • red floyd

      #3
      Re: Writing Singleton Classes

      cppaddict wrote:
      [color=blue]
      > Hi,
      >
      > In this tutorial on singleton class in C++
      > (http://gethelp.devx.com/techtips/cpp.../10min0200.asp) the
      > author gives two implementations of a simple singleton class, claiming
      > that only the first is safe for multi-threaded appliactions. I want
      > to know why this so.
      >
      > The class is as follows:
      >
      > class Singleton
      > {
      > public:
      > static Singleton* Instance();
      > protected:
      > Singleton();
      > Singleton(const Singleton&);
      > Singleton& operator= (const Singleton&);
      > private:
      > static Singleton* pinstance;
      > };[/color]

      Looks to me like the *first* instance isn't thread safe, but the second is!
      [color=blue]
      > The first implementation is:
      >
      > Singleton* Singleton::pins tance = 0;// initialize pointer
      > Singleton* Singleton::Inst ance ()
      > {
      > if (pinstance == 0) // is it the first call?
      > {[/color]
      What happens if a context switch occurs right here? After the if
      statemnt, but before the new?[color=blue]
      > pinstance = new Singleton; // create sole instance
      > }
      > return pinstance; // address of sole instance
      > }
      > Singleton::Sing leton()
      > {
      > //... perform necessary instance initializations
      > }
      >
      > The second implementation makes a small change to the constructor:[/color]
      Not a constructor, but the Singleton accessor.[color=blue]
      >[/color]
      As far as I can tell, this *is* thread safe.[color=blue]
      > Singleton* Singleton::Inst ance ()
      > {
      > static Singleton inst;
      > return &inst;
      > }
      >
      > The author notes that the second implementation is optimized for
      > single-threaded applications. Why would it not also work for
      > multi-threaded applications?[/color]

      I think the author is full of it, but that's just *MY* opinion... I
      could be wrong.

      Comment

      • cppaddict

        #4
        Re: Writing Singleton Classes

        [color=blue]
        >Now, the first implementation is also problematic, and has
        >exactely the same problem: initialisation must be protected
        >by a mutex or something...
        >
        >Benoit[/color]

        Thanks for the reference. That's very interesting....

        What is a mutex though? After reading that article it seems that
        Singletons are never thread safe.

        Thanks,
        cpp

        Comment

        • Tim Clacy

          #5
          Re: Writing Singleton Classes

          cppaddict wrote:[color=blue]
          > Hi,
          >
          > In this tutorial on singleton class in C++
          > (http://gethelp.devx.com/techtips/cpp.../10min0200.asp) the
          > author gives two implementations of a simple singleton class, claiming
          > that only the first is safe for multi-threaded appliactions. I want
          > to know why this so.[/color]

          cppaddict,

          The first implementation needs a slight change to be thread-safe:

          Singleton* Singleton::Inst ance ()
          {
          // In the common case, simply return the existing instance (no
          locking required)
          //
          if (pinstance != 0)
          return pinstance;

          // If there was no instance above, we need to lock now and
          double-check whether
          // another thread created an instance in between the check above and
          now
          //
          Lock();
          if (pinstance == 0)
          pinstance = new Singleton;
          Unlock();

          return pinstance;
          }

          There are a dozen or so Singleton articles on CodeProject; the following is
          very good and covers threading issues:

          Singleton Pattern: A review and analysis of existing C++ implementations



          Tim


          Comment

          • Benoit Mathieu

            #6
            Re: Writing Singleton Classes

            > What is a mutex though? After reading that article it seems that[color=blue]
            > Singletons are never thread safe.[/color]

            Mutex means Mutual Exclusion (it's a mechanism that ensures
            that at most one thread accesses a particular object at a
            given time). See Tim Clacy's post: Lock() prevents other
            threads from executing the sequence until Unlock() has been
            called. Lock and Unlock can usually not be implemented with
            high level standard instructions. It always involves some
            machine specific instructions (disabling interruptions, ...)
            but this is going to be very off-topic here and you will
            have to switch to another group to get informations about
            locking mechanisms.

            Local static variables are not safe, but implementing a
            Singleton with Tim Clacy's code is safe (provided that
            Lock() and Unlock() are correct, of course) :

            Lock();
            if (pinstance == 0)
            pinstance = new Singleton;
            Unlock();

            Benoit

            Comment

            • DaKoadMunky

              #7
              Re: Writing Singleton Classes

              Neither of the solutions in the article originally referenced are thread safe.

              In a threaded program both could lead to undesired behavior such as double
              construction or premature access.

              One of the respondents to this thread posted an example of the Double Checked
              Locking idiom.

              Apparently even that is problematic as discussed by Scott Meyers in the
              document @ http://www.nwcpp.org/Downloads/2004/DCLP_notes.pdf

              Comment

              • Xenos

                #8
                Re: Writing Singleton Classes


                "red floyd" <no.spam@here.d ude> wrote in message
                news:hgPoc.7978 $Jx.6911@newssv r27.news.prodig y.com...[color=blue]
                > As far as I can tell, this *is* thread safe.[color=green]
                > > Singleton* Singleton::Inst ance ()
                > > {
                > > static Singleton inst;
                > > return &inst;
                > > }
                > >[/color][/color]
                No, its not. If the first thread is in the middle of construction, and get
                preempted, the object is in an unknown state when the second thread attempts
                access. This is safe from order dependencies during init., but not thread
                safe. The opposite is true for the first form. It is thread-safe because
                it is initialized before the application's main procedure runs and therefore
                before the program can spawn any threads. It is not safe from order
                dependencies if a staticly constructed object from a different file attempts
                access to it during construction.



                Comment

                • Xenos

                  #9
                  Re: Writing Singleton Classes


                  "Xenos" <dont.spam.me@s pamhate.com> wrote in message
                  news:c80l8r$7sr 4@cui1.lmms.lmc o.com...[color=blue]
                  >
                  > "red floyd" <no.spam@here.d ude> wrote in message
                  > news:hgPoc.7978 $Jx.6911@newssv r27.news.prodig y.com...[color=green]
                  > > As far as I can tell, this *is* thread safe.[color=darkred]
                  > > > Singleton* Singleton::Inst ance ()
                  > > > {
                  > > > static Singleton inst;
                  > > > return &inst;
                  > > > }
                  > > >[/color][/color]
                  > No, its not. If the first thread is in the middle of construction, and[/color]
                  get[color=blue]
                  > preempted, the object is in an unknown state when the second thread[/color]
                  attempts[color=blue]
                  > access. This is safe from order dependencies during init., but not thread
                  > safe. The opposite is true for the first form. It is thread-safe because
                  > it is initialized before the application's main procedure runs and[/color]
                  therefore[color=blue]
                  > before the program can spawn any threads. It is not safe from order
                  > dependencies if a staticly constructed object from a different file[/color]
                  attempts[color=blue]
                  > access to it during construction.
                  >
                  >
                  >[/color]

                  Looked at code to quick, the first is not thread-safe either. I thought it
                  was constructor at startup, not is not.



                  Comment

                  • Xenos

                    #10
                    Re: Writing Singleton Classes


                    "Xenos" <dont.spam.me@s pamhate.com> wrote in message
                    news:c80ldi$7sr 5@cui1.lmms.lmc o.com...[color=blue]
                    > Looked at code to quick, the first is not thread-safe either. I thought[/color]
                    it[color=blue]
                    > was constructor at startup, not is not.[/color]

                    Geesh! Now I'm just typing to fast.

                    ....constructed at strartup, but it is not!


                    Comment

                    • Alexander Terekhov

                      #11
                      Re: Writing Singleton Classes


                      DaKoadMunky wrote:
                      [...][color=blue]
                      > One of the respondents to this thread posted an example of the Double Checked
                      > Locking idiom.[/color]

                      The idiom has only one check for locking, not two. I guess that
                      someone had called it "the DCL" after 10th drink or so (they say
                      that after about 10th drink one tends not to count correctly
                      anymore). A much better name is "Double Checked Serialized
                      Initialization" . There are two variations of DCSI. One with
                      atomic<>-with-msync::<stuff> and more portable one with thread-
                      specific data (e.g. "thread_specifi c_ptr<>") instead of
                      atomic<>-with-msync::<stuff> (and I don't mean thread-specific
                      singletons). There is also "Double Checked Concurrent
                      Initialization" idiom (lock-less and not for "singletons ").


                      [color=blue]
                      >
                      > Apparently even that is problematic as discussed by Scott Meyers in the
                      > document @ http://www.nwcpp.org/Downloads/2004/DCLP_notes.pdf[/color]

                      Not bad up to Pg. 22. "Multiprocessor s, Cache Coherency, and
                      Memory Barriers" part is somewhat screwed. For example, Pg. 34
                      and Pg. 35:

                      Keyboard* temp = pInstance;
                      Perform acquire;
                      ...

                      (that notation sucks, BTW) is not really the same (with
                      respect to reordering) as

                      Keyboard* temp = pInstance;
                      Lock L1(args); // acquire
                      ...

                      because the later can be transformed to

                      Lock L1(args); // acquire
                      Keyboard* temp = pInstance;
                      ...

                      While it does stress the point of Pg. 36, the difference is
                      quite significant and it can really hurt you in some other
                      context. Beware.

                      regards,
                      alexander.

                      P.S. atomic<> is the way to go.

                      Comment

                      • Joe Seigh

                        #12
                        Re: Writing Singleton Classes



                        Alexander Terekhov wrote:[color=blue]
                        >
                        > DaKoadMunky wrote:
                        > [...][color=green]
                        > > One of the respondents to this thread posted an example of the Double Checked
                        > > Locking idiom.[/color]
                        >
                        > The idiom has only one check for locking, not two. I guess that
                        > someone had called it "the DCL" after 10th drink or so (they say
                        > that after about 10th drink one tends not to count correctly
                        > anymore). A much better name is "Double Checked Serialized
                        > Initialization" . There are two variations of DCSI. One with
                        > atomic<>-with-msync::<stuff> and more portable one with thread-
                        > specific data (e.g. "thread_specifi c_ptr<>") instead of
                        > atomic<>-with-msync::<stuff> (and I don't mean thread-specific
                        > singletons). There is also "Double Checked Concurrent
                        > Initialization" idiom (lock-less and not for "singletons ").
                        >
                        > http://google.com/groups?selm=40867B...FEBFE%40web.de[/color]

                        Or you would just access the singleton via a reference in a handle
                        or object where correct visibility was established in the handle
                        or objects ctor, said objects being handled in the usual "threadsafe
                        as int" idiom.

                        ....[color=blue]
                        >
                        > P.S. atomic<> is the way to go.[/color]

                        except that there are several possibilities for atomic<> semantics
                        besides just the mutable/immutable stuff. There's atomic<T> vs.
                        atomic<*T>.

                        Joe Seigh

                        Comment

                        • Alexander Terekhov

                          #13
                          Re: Writing Singleton Classes


                          Joe Seigh wrote:
                          [...][color=blue]
                          > Or you would just access the singleton via a reference in a handle
                          > or object where correct visibility was established in the handle
                          > or objects ctor,[/color]

                          Yep. For example auto_unlock_ptr <>. That's what you need for mutable
                          "singletons " that don't use atomic<> internally. They need a lock
                          anyway and, usually, there's no problem to initialize the lock eagerly
                          or use something like lazy create-open-named-mutex trick on windows.
                          The situation is a bit different for immutable things (but you can
                          still use "expensive" get_instance() and cache the reference on the
                          callers side; in a way, that's what the TSD variation of DCSI does
                          internally).

                          regards,
                          alexander.

                          Comment

                          • Joe Seigh

                            #14
                            Re: Writing Singleton Classes



                            Alexander Terekhov wrote:[color=blue]
                            >
                            > Joe Seigh wrote:
                            > [...][color=green]
                            > > Or you would just access the singleton via a reference in a handle
                            > > or object where correct visibility was established in the handle
                            > > or objects ctor,[/color]
                            >
                            > Yep. For example auto_unlock_ptr <>. That's what you need for mutable
                            > "singletons " that don't use atomic<> internally. They need a lock
                            > anyway and, usually, there's no problem to initialize the lock eagerly
                            > or use something like lazy create-open-named-mutex trick on windows.
                            > The situation is a bit different for immutable things (but you can
                            > still use "expensive" get_instance() and cache the reference on the
                            > callers side; in a way, that's what the TSD variation of DCSI does
                            > internally).
                            >[/color]

                            I mean caching the reference in the object. In the object's ctor
                            you use DCL or one of your acronyms to create the singleton and
                            store the reference to the singleton in the object. The "safe
                            as int" visibility semantics guarantee proper visibility to the
                            singleton the same way they guarantee proper visibility of any
                            of the object's fields. It's not specific or local to the thread,
                            it's specific to the object using proper ownership rules.

                            If you are only accessing the singleton via the object's methods,
                            then it's pretty much transparent to the user. The only way
                            the user could get into trouble is by violating the "safe as int"
                            rule and they'd be in trouble even without a singleton involved.

                            Joe Seigh

                            Comment

                            • Mark A. Gibbs

                              #15
                              Re: Writing Singleton Classes


                              DaKoadMunky wrote:

                              [color=blue]
                              > One of the respondents to this thread posted an example of the Double Checked
                              > Locking idiom.
                              >
                              > Apparently even that is problematic as discussed by Scott Meyers in the
                              > document @ http://www.nwcpp.org/Downloads/2004/DCLP_notes.pdf[/color]

                              am i missing something here? why wouldn't this work:

                              Singleton* Singleton::Inst ance()
                              {
                              if (pinstance != 0)
                              return pinstance;

                              Lock();

                              if (pinstance == 0)
                              pinstance = makeSingleton() ;

                              Unlock();

                              return pinstance;
                              }

                              Singleton* Singleton::make Singleton()
                              {
                              return new Singleton;
                              }

                              mark

                              Comment

                              Working...