Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

thread Safe singleton

5 views
Skip to first unread message

Ramesh Kadambi

unread,
Jan 28, 2002, 10:14:59 PM1/28/02
to
Hi Folks,

I am aware and have read some of the postings on thread safe singletons and
their implementation, I cound not find the following implementation as a
possible thread safe method. I think the creation of the singleton is
thread safe because the singleton is created when g_StaticSingletonCreator
is instantiated which is before any piece of code is executed.

Here it goes ....

singleton.h

//
// Singleton
//
// This file implements a singleton class.
//

#ifndef __SINGLETON_H__

#define __SINGLETON_H__
#include <iostream>

using namespace std;

class CSingleton
{
private:
CSingleton();
CSingleton(CSingleton& Singleton);

public:
static CSingleton* CreateSingleton();
virtual ~CSingleton();

void Test(int Value);

};

static class CSingletonCreator
{
private:
static int m_CreatorCount;
CSingleton* MySingleton;
public:
CSingletonCreator()
{
if( m_CreatorCount++ == 0 )
{
MySingleton = CSingleton::CreateSingleton();
}

cout << "no of Singleton Creators " << m_CreatorCount << endl;
};

~CSingletonCreator()
{
if( m_CreatorCount-- )
{
cout << "no of objects " << m_CreatorCount;
}
};

} g_StaticSingletonCreator;


#endif

singleton.cpp

//
// Singleton
//
// This file implements a singleton class.
//

#include "Singleton.h"

int CSingletonCreator::m_CreatorCount = 0;

CSingleton::CSingleton()
{
}

CSingleton::CSingleton( CSingleton& Singleton )
{
}


CSingleton* CSingleton::CreateSingleton()
{
static CSingleton TheOnlyInstance;

return &TheOnlyInstance;

}

CSingleton::~CSingleton()
{
}


void CSingleton::Test(int Value)
{
cout << "The Test Worked" << this ;
cout << " Value " << Value << endl ;
}

Ramesh


Paul Pluzhnikov

unread,
Jan 29, 2002, 1:00:19 AM1/29/02
to
"Ramesh Kadambi" <ramesh....@verizon.net> wrote in message
news:Tso58.3679$pb....@nwrddc01.gnilink.net...

> I am aware and have read some of the postings on thread safe singletons
and
> their implementation, I cound not find the following implementation as a
> possible thread safe method.

Because it is not thread safe, perhaps ?-)

> I think the creation of the singleton is
> thread safe because the singleton is created when g_StaticSingletonCreator
> is instantiated which is before any piece of code is executed.

What made you believe your singleton constructor is
executed "before any (other) piece of code" ?

You use "cout" in your singleton constructor.
Cout has a constructor of its own.

Does ostream::ostream() execute before, after, or
during CSingleton::CSingleton() ?

A comprehensive treatment of the subject could be found in:
http://www.amazon.com/exec/obidos/ASIN/0201704315
Modern C++ Design: Generic Programming and Design Patterns Applied
by Andrei Alexandrescu


Ramesh Kadambi

unread,
Jan 29, 2002, 10:05:17 AM1/29/02
to

"Paul Pluzhnikov" <ppluz...@earthlink.net> wrote in message
news:TTq58.3593$ks5.3...@newsread1.prod.itd.earthlink.net...

> "Ramesh Kadambi" <ramesh....@verizon.net> wrote in message
> news:Tso58.3679$pb....@nwrddc01.gnilink.net...
> > I am aware and have read some of the postings on thread safe singletons
> and
> > their implementation, I cound not find the following implementation as a
> > possible thread safe method.
>
> Because it is not thread safe, perhaps ?-)

I think I understand the issue now. After thinking a bit I think I
understand why it would not be thread safe. Without locking you cannot
ensure the thread safety of the code.

>
> > I think the creation of the singleton is
> > thread safe because the singleton is created when
g_StaticSingletonCreator
> > is instantiated which is before any piece of code is executed.
>
> What made you believe your singleton constructor is
> executed "before any (other) piece of code" ?
>

Since globals and static variables are initialized before any piece of code
from a translation unit is executed and the Singleton header file is
included in all the units that need it g_StaticSingletonCreator will be
initialized before any piece of code in the unit is executed. But did not
realize, that does not make it thread safe especially if it is part of a
library. Since two threads could be doing the same and you are right there
is no avoiding the mutexes.

I should have thought a little further before I posted my stuff.


Ramesh

Alexander Terekhov

unread,
Jan 29, 2002, 11:18:56 AM1/29/02
to
"Ramesh Kadambi" <ramesh....@verizon.net> wrote in message news:<Tso58.3679$pb....@nwrddc01.gnilink.net>...
> Hi Folks,
>
> I am aware and have read some of the postings on thread safe singletons and
> their implementation, I cound not find the following implementation as a
> possible thread safe method. I think the creation of the singleton is
> thread safe because the singleton is created when g_StaticSingletonCreator
> is instantiated which is before any piece of code is executed.

Do you mean main() function? ;-)

Well, in PTHREADS/C*** you might use pthread_once()
for thread-safe "dynamic package" (lazy-) inits.
Or you could use statically initialized mutexes.
(perhaps even with tsd-based DCL "optimization" ;)

Personally, I tend to use pthread_once for
*immutable* "lazy-singletons" (such as tsd-
keys, for example), because it has a good
chance to result in less synchronization
overhead than mutex, IMHO. For *mutable*
"lazy-singletons" you need a lock anyway,
so I think that pthread_once does not provide
you much at all in addition to a statically
initialized mutex, which could be used for
both construction and further usage sync.
(static get() method could just "return" a
thread-private auto-"smart_ref/ptr" which
would just automatically unlock on its
destruction or perhaps even a thread-shareable
class instance that would provide extra lock/
unlock calls in addition to the singleton's
interface, for example).

regards,
alexander.

[***] some C++ compilers generate
thread-safe local statics dynamic
init code, but unfortunately, there
is no standard way to control it.
Personally, I would not want to have
that extra sync. overhead neither
for my thread-private lazy-singletons
nor for my shared-mutable ones, IMHO.

Ramesh Kadambi

unread,
Jan 29, 2002, 2:11:31 PM1/29/02
to

"Alexander Terekhov" <tere...@web.de> wrote in message
news:c29b5e33.02012...@posting.google.com...

> "Ramesh Kadambi" <ramesh....@verizon.net> wrote in message
news:<Tso58.3679$pb....@nwrddc01.gnilink.net>...
> > Hi Folks,
> >
> > I am aware and have read some of the postings on thread safe singletons
and
> > their implementation, I cound not find the following implementation as a
> > possible thread safe method. I think the creation of the singleton is
> > thread safe because the singleton is created when
g_StaticSingletonCreator
> > is instantiated which is before any piece of code is executed.
>
> Do you mean main() function? ;-)
>

Yep, apologies if I were not clear. But then I realized, if the singleton
is part of a shared library or dll, it seems to me the only way to safely
obtain a reference to it is by using a mutex to lock the access. The
singleton I implemented worked because the header was included in the
translation unit with main() and it so happened that the threads were
created from main and by the time the threads obtained the reference
everything was cool.

> Well, in PTHREADS/C*** you might use pthread_once()
> for thread-safe "dynamic package" (lazy-) inits.
> Or you could use statically initialized mutexes.
> (perhaps even with tsd-based DCL "optimization" ;)
>

I am not sure how you would use pthread_once since the initialization
routine is of the form (void) (*init_routine)(), when you expect the
routine in the case of a singleton object to construct and return a
reference to it safely.

> Personally, I tend to use pthread_once for
> *immutable* "lazy-singletons" (such as tsd-
> keys, for example), because it has a good
> chance to result in less synchronization
> overhead than mutex, IMHO. For *mutable*
> "lazy-singletons" you need a lock anyway,
> so I think that pthread_once does not provide
> you much at all in addition to a statically
> initialized mutex, which could be used for
> both construction and further usage sync.
> (static get() method could just "return" a
> thread-private auto-"smart_ref/ptr" which
> would just automatically unlock on its
> destruction or perhaps even a thread-shareable
> class instance that would provide extra lock/
> unlock calls in addition to the singleton's
> interface, for example).
>
> regards,
> alexander.
>

I perfectly agree with you here (-:

Thank you,
Ramesh


Alexander Terekhov

unread,
Jan 30, 2002, 4:00:59 AM1/30/02
to
"Ramesh Kadambi" <ramesh....@verizon.net> wrote in message news:<DtC58.4269$pb....@nwrddc01.gnilink.net>...
[...]

> > Well, in PTHREADS/C*** you might use pthread_once()
> > for thread-safe "dynamic package" (lazy-) inits.
> > Or you could use statically initialized mutexes.
> > (perhaps even with tsd-based DCL "optimization" ;)
> >
>
> I am not sure how you would use pthread_once since the initialization
> routine is of the form (void) (*init_routine)(), when you expect the
> routine in the case of a singleton object to construct and return a
> reference to it safely.

Just using an extra static/global variable:

http://groups.google.com/groups?as_umsgid=3AC07BBB.4F52286E%40web.de

which I somewhat dislike:

http://groups.google.com/groups?as_umsgid=3A9F8B22.D9417FD1%40web.de

Also, C++ exceptions "might" be an issue (but I strongly
believe that on any *real* PTHREAD/*C++* impl that should
NOT be the case):

http://groups.google.com/groups?as_umsgid=3AF9B7BD.DB69CA90%40dollywood.itp.tuwien.ac.at
http://groups.google.com/groups?as_umsgid=3AFFACBF.1CB23112%40web.de

And finally, I just hope that in the next revision of the
standard, pthread_once will just replace pthread_cond_signal
and pthread_cond_broadcast in the list of functions providing
memory synchronization (4.10)... consider that perhaps we could
get rid of ONE single line! That is a real saving!! ;-)

regards,
alexander.

Ramesh Kadambi

unread,
Jan 30, 2002, 10:31:23 AM1/30/02
to

"Alexander Terekhov" <tere...@web.de> wrote in message
news:c29b5e33.02013...@posting.google.com...

That was pretty neat, now I know lot more than what I knew. Great and
thank you.

Ramesh


Alexander Terekhov

unread,
Feb 1, 2002, 6:05:15 AM2/1/02
to
"Ramesh Kadambi" <ramesh....@verizon.net> wrote in message news:<flU58.6166$pb....@nwrddc01.gnilink.net>...

> "Alexander Terekhov" <tere...@web.de> wrote in message
> news:c29b5e33.02013...@posting.google.com...
[...]

> > And finally, I just hope that in the next revision of the
> > standard, pthread_once will just replace pthread_cond_signal
> > and pthread_cond_broadcast in the list of functions providing
> > memory synchronization (4.10)... consider that perhaps we could
> > get rid of ONE single line! That is a real saving!! ;-)

A friend of mine asked me privately to clarify
this REPLACE bit. I think that it will be a not
entirely bad idea if I do it here, so that The
Threading Wars veterans/more educated people
than me-stupid, would have a chance to correct[1]
me in my attempt to prove that pthread_cond_signal
and pthread_cond_broadcast have nothing to do with
memory synchronization and therefore should be
*REMOVED* from 4.10 list (Base Definitions).

My proof is based on DS-impl.("tm";-)[2] of condition
variable. If you think (like I personally strongly do)
that

wait: unlock(mtx);sleep(random());lock(mtx);

implementation is indeed CORRECT one (predictable
scheduling behavior aside for this proof, since
such signaling needs to be done while *holding the
mutex*), then you should come to the conclusion that
DS-impl of signal/broadcast should basically be:

signal: NOOP

broadcast: NOOP

Now I claim that instead of NOOPs you could add
as many memory barriers as you like, but it won't
do it any better than memory synchronization already
provided by mtx *MUTEX* in "wait". That is why I
strongly believe that pthread_cond_signal and
pthread_cond_wait should just be REPLACED by
pthread_once in 4.10.

Am I wrong?

regards,
alexander.

[1] Feel free to jump in and raise your objections
but beware that a couple of months ago I
contacted The Master of Black&White Threading
Science[3] ;-) and the answer was basically that
(my own words/short-interpretation) "the inclusion
of these two functions in 4.10 was a harmless
accident", if my memory serves.

[2] http://groups.google.com/groups?as_umsgid=c29b5e33.0201230601.61473a67%40posting.google.com

[3] right, that is <David.B...@compaq.com>,
who *I just hope* is now busy with finishing the
brand new 2nd edition[4] of
http://www.awl.com/cseng/titles/0-201-63392-2/
;-)

[4] Among other things, will be SYNCHRONIZED with recently
published http://www.unix-systems.org/version3/ ;-)

0 new messages