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

A few questions about singletons...

8 views
Skip to first unread message

Somebody

unread,
Sep 24, 2009, 5:03:29 PM9/24/09
to
So, I've been programming for 16 yrs in C++ and it seems like all the OO
interviews these days think you need to know design patterns to be a good
(or even decent) programmer :p. What ya gonna do eh? :)...

Anyways, this is what I have for my singleton class.

class CSingleton
{
protected:

CSingleton()
{
printf("CSingleton()\n");
}

~CSingleton()
{
printf("~CSingleton()\n");
}

static CSingleton* m_pInst;

public:

static CSingleton* GetInstance()
{
if (m_pInst == NULL)
m_pInst = new CSingleton;

return m_pInst;
}
};

CSingleton* CSingleton::m_pInst = NULL;

int _tmain(int argc, _TCHAR* argv[])
{
CSingleton* p1 = CSingleton::GetInstance();
CSingleton* p2 = CSingleton::GetInstance();
printf("--> %x %x\n", p1, p2);
return 0;
}

Works fine... except...

1) what is the interview approved way to clean up the created object? Having
a static "clean up" method that the user is responsible for calling seems
completely retarded and anti-encapsulation. I've seen some solutions that
create a second CSingletonDestroyer class as static and pass in the pointer.
Then when the CSingletonDestroyer class is killed naturally, it kills the
CSingleton...

2) but the CSingletonDestroyer() class brings up thread safeness issues...
if I wrap my GetInstance() in a critical section how does the critical
section get initialized and cleaned up? I guess I can use a mutex, which
will solve the init problem since that can be static init'ed, but wheres the
clean up?

Keep in mind, I'm doing this for Windows jobs, so no "linux only" solutions
:).


cpisz

unread,
Sep 24, 2009, 11:47:14 PM9/24/09
to

Some interviewers seem to like to puff themselves up with some
knowledge they read about, but don't understand the pitfalls of. I
wouldn't want to work with someone like that anyway. I've had several
leads that thought they were hot poopy because they read the gang of 4
and learned some new words like "singleton". Ends up those same guys
created 6 months worth of debugging for me, because they don't
understand the pitfalls. I myself, plainly do not use singletons
anymore. It does not mean I don't understand it, it means I've decided
passing a reference to an object that is clearly documented has been
less of a headache then debugging through global and static release at
program exit. There is always going to be some guy that creates an
unwanted dependency on a singleton and doesn't understand the mess
they are making. You cannot control the actions of others, but you can
try to minimize the mistakes they will make.

I have to date to see a singleton that did not involve a global or
static of some sort. The problem of another global or static depending
on it is unescapable without shockers tied to the entire companies
nipples. Release order of globals and statics is undefined. Sometimes
it will break, sometimes not, but it will always give you a massive
headache when you get to debugging this reappearing/disappearing
problem.

Design patterns are great. Knowing about them is also great. Knowing
about the pitfalls is better. Knowing that everyone that touches your
code probably won't is excellance.
Thus I think the answer to 1) is - There is no compeltely safe way to
cleanup. Everyone needs to be aware of that and the dependency problem
it creates.
2) why bother with a static destroyer? You are just moving the issue
to another place. Maybe I would need to see a specific example to
understand....

karthik

unread,
Sep 25, 2009, 1:40:56 AM9/25/09
to
Hi,

Idea of a singleton class is to have a common instance which can be
used in other objects. If someone creates or gets an object, he has to
delete or release it also.

> 1) what is the interview approved way to clean up the created object? Having
> a static "clean up" method that the user is responsible for calling seems
> completely retarded and anti-encapsulation.

I couldn't really understand what does the above mean by retarded and
anti-encapsulation method. If some user creates an object, he should
delete it somehow. Since interface of the class suggests the person to
use "GetInstance", it should have reverse method like
"ReleaseInstance" which makes sure deletion of instance will happen if
no one is using the instance currently.

* Initially there will be no instance.

* Some user calls "GetInstance", static userCount variable will be
one, hence an object will be created. Further calls to "GetInstance"
will simply
increase userCount.

* "ReleaseInstance" decrements userCount and deletes the object, if
userCount is zero.

Missing of calling "ReleaseInstance" will lead to Memory leak,
obviously. Static "userCount" variable is un-avoidable. But It won't
cause memory leak.

Regards,
Karthik.

Michael Doubez

unread,
Sep 25, 2009, 4:05:38 AM9/25/09
to
On 24 sep, 23:03, "Somebody" <someb...@cox.net> wrote:
> So, I've been programming for 16 yrs in C++ and it seems like all the OO
> interviews these days think you need to know design patterns to be a good
> (or even decent) programmer :p. What ya gonna do eh? :)...
>
> Anyways, this is what I have for my singleton class.

Some classify singleton as an anti-pattern. It has been too much
confused with globals (IMO particularly in C++ because of the idiom
solving the initialisation order issue).

>
> class CSingleton
> {
> protected:
>
>  CSingleton()
>  {
>   printf("CSingleton()\n");
>  }
>
>  ~CSingleton()
>  {
>   printf("~CSingleton()\n");
>  }
>
>  static CSingleton* m_pInst;
>
> public:
>
>  static CSingleton* GetInstance()
>  {
>   if (m_pInst == NULL)
>    m_pInst = new CSingleton;
>
>   return m_pInst;
>  }
>
> };
>
> CSingleton* CSingleton::m_pInst = NULL;

IIRC, you have implemented the Gamma singleton; it has a number of
pitfall you may search on internet.

[snip]

>
> Works fine... except...
>
> 1) what is the interview approved way to clean up the created object? Having
> a static "clean up" method that the user is responsible for calling seems
> completely retarded and anti-encapsulation. I've seen some solutions that
> create a second CSingletonDestroyer class as static and pass in the pointer.
> Then when the CSingletonDestroyer class is killed naturally, it kills the
> CSingleton...

You can use a Meyer singleton which solve the initialisation order
issue:

static CSingleton& GetInstance()
{
CSingleton static_instance;

return static_instance;
}

And the cleanup is made at termination. The cleanup of a singleton is
delicate because you don't known how is currently using it (it is even
worse when in a DLL); you should let the system decide when it is no
longer needed.

> 2) but the CSingletonDestroyer() class brings up thread safeness issues...
> if I wrap my GetInstance() in a critical section how does the critical
> section get initialized and cleaned up? I guess I can use a mutex, which
> will solve the init problem since that can be static init'ed, but wheres the
> clean up?

Singleton in multithreading environment is a delicate matter. There is
currently no standard way of doing it reliably (except in the next C++
standard).

You may search "C++ and the Perils of Double-Checked Locking" for a
detailed explanation.

--
Michael

Noah Roberts

unread,
Sep 25, 2009, 1:44:22 PM9/25/09
to
In article <M8Rum.245763$ZN.1...@newsfe23.iad>, some...@cox.net
says...

>
> So, I've been programming for 16 yrs in C++ and it seems like all the OO
> interviews these days think you need to know design patterns to be a good
> (or even decent) programmer :p. What ya gonna do eh? :)...

It's amazing you've made it 16 years and never learned patterns.
Patterns ARE central to solid development. Perhaps you've been using
them and don't even know it. That's cool, but the problem is that
patterns are also a language of architectural designs. When I, as a
lead, say, "Perhaps a template method would be a good implementation of
this," I hope you know what I'm talking about so I don't have to explain
it to you. Same as if I said, "I implemented the controller with a
basic state pattern that emits commands," in a code review--I want
everyone in the room to know that that sentance means because it saves a
good 20 minutes. You've almost certainly run into this pattern and used
it on your own but I'd still have to explain myself to someone that
should already know what I'm talking about. This is, quite frankly, way
more important than being an expert in how to implement them.

People that don't know patterns, at least in a rudimentary sense, are
more difficult to communicate with.

Further, the fact that you never learned them is a BIG red flag. Basic
curiosity should have made you look into them even if you decided they
were useless. That you didn't care enough to know patterns after 16
years indicates a lack of dedication to your field. People that think
they know enough already usually tend not to be the best developers out
there.

>
> Anyways, this is what I have for my singleton class.
>
> class CSingleton

This is an orange flag for me. Prefixing class names with C indicates
attachment to hungarian notation. I'd probably pester you about this
choice of name in an interview. It wouldn't pass a code review in my
shop if 'C' stood for "class".

> {
> protected:
>
> CSingleton()
> {
> printf("CSingleton()\n");

This would be another red flag for me. Use of printf indicates someone
too attached to the all but obsolete C interface. I'd be worried you
use char[] and malloc too. Different environments may be different but
as a pure C++ development team we avoid the C API almost
entirely...exception being the math library. I'd much rather see
"std::cout << xxx"

> }
>
> ~CSingleton()
> {
> printf("~CSingleton()\n");
> }
>
> static CSingleton* m_pInst;
>
> public:
>
> static CSingleton* GetInstance()
> {
> if (m_pInst == NULL)
> m_pInst = new CSingleton;
>
> return m_pInst;
> }
> };
>
> CSingleton* CSingleton::m_pInst = NULL;

This is certainly one implementation. An interviewer is probably only
interested that you know what the Singleton is for, why you'd use it,
why you wouldn't, and at least one method to implement it....and if
you're interviewing for an advanced position I'd ask you what the
problems are with your chosen implementation and might ask for an
alternative. One of which is to stick m_pInst as a static variable in
the function that fetches it:

static CSingleton * GetInstance()
{
static CSingleton * instance = new CSingleton;
return instance;
}

Any time you use a singleton you have to address conditions specific to
your given problem. Thread safety is certainly a concern in threaded
environments. Most times when you use a singleton you're not actually
worried about when it deletes and how it gets cleaned up. Sometimes you
are.

You should learn more than the Singleton pattern. The Singleton is
probably the most commonly known but most useless pattern out there. As
someone mentioned it is often considered an anti-pattern. There are
actually very few cases when you should be using one. As an interviewer
I'd be much more impressed if you knew and understoond template method,
chain of responsibility, decorator, or proxy. Hell, even the NullObject
is generally more useful. If you could name and explain these I'd be
more confident that you actually know and understand patterns rather
than just learning enough to pass the basic pattern exam.

I do run into people like you and have accepted them in interviews so
long as they are not hostile to patterns. I, perhaps unlike many,
realize that patterns are consequences of the problem and expose
themselves so obviously that anyone good is going to come upon them
independently. When I first learned them I found I'd used many before.
If you don't know the language I might push a bit to see if you might
recognize one or two if I describe them. One very important part of
this though is that you're not too stubborn to accept their usefulness,
or at the very least accept the fact that you'd be required to learn
them.

The problem I'd see in your sample code and your position of not knowing
patterns is that you have some bad habbits to unlearn and some new stuff
that you need to learn. I'd probably hit you hard to see what your
reaction is. People with 16 years of experience are often too britile
and stubborn to adapt and can be, in many ways, a worse hire than an
intern. Frankly, I'd rather hire a green programmer hands down in
almost every case.

Joshua Maurice

unread,
Sep 25, 2009, 2:45:57 PM9/25/09
to
On Sep 25, 1:05 am, Michael Doubez <michael.dou...@free.fr> wrote:
> You can use a Meyer singleton which solve the initialisation order
> issue:
>
> static CSingleton& GetInstance()
> {
>  CSingleton static_instance;
>
>  return static_instance;
>
> }
>
> And the cleanup is made at termination. The cleanup of a singleton is
> delicate because you don't known how is currently using it (it is even
> worse when in a DLL); you should let the system decide when it is no
> longer needed.

Suffice to say, actually suggesting the simplest Meyer's singleton is
bad advice. Frankly, I've made so many mistakes on this topic recently
that I'll just point you to the thread where someone more
knowledgeable than me suggests more correct ways to do this.

http://groups.google.com/group/comp.lang.c++/browse_thread/thread/bca4044f40befc6a#

1- Your singleton may cause static deinit issues. If you can leak it,
just leak it. Otherwise, it'll work correctly if all other statics
call getSingleton in their constructors. This will guarantee correct
destruction order, Last In First Out.

2- It's not thread-safe. There's the simple ways to do this correctly
which come with the caveat that "No nontrivial threads during static
init". Alternatively, use the more complex designs of Chris M.
Thomasson, which just guarantee single correct construction with
minimal overhead. There are several, depending on platform, and
exactly what guarantees you want.

Short version: Actually doing a correct singleton in C++ is hard (tm).
It requires you to understand many nuances of the language, and things
outside the language, like static initialization order fiasco, static
de-initialization order fiasco, deep knowledge of thread-safety, etc.

As long as I'm here, I might as well suggest this excellent paper as
well, which covers the more common pitfall I've seen regarding
singletons, and more generally a lack of understanding of modern real-
world threading.

http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf

Chris M. Thomasson

unread,
Sep 27, 2009, 9:37:57 PM9/27/09
to
"Joshua Maurice" <joshua...@gmail.com> wrote in message
news:5f0a678c-5308-4fca...@z4g2000prh.googlegroups.com...

FWIW, the "minimal" techniques do have there overheads, which usually
present themselves in the form of atomic RMW instructions and
acquire/release semantics. Unfortunately, these operations can be fairly
expensive. However, using strongly-thread safe atomic reference counting can
greatly simplify creating robust singletons. Yes, that type of reference
counting may, or may not, involve all the overheads I mentioned, and perhaps
more; so be it. It's all a mess of tradeoffs and benefits anyway. You will
simply have to dig deep and find the scheme which can work well within the
framework presented by you're specific application.


> Short version: Actually doing a correct singleton in C++ is hard (tm).

IMVHO, it sure as heck simplifies things if your program is single-threaded
or you guarantee that no threads will ever be created before `main()'!!!

Yikes!

;^O

Krice

unread,
Sep 28, 2009, 3:15:31 AM9/28/09
to
On 25 syys, 20:44, Noah Roberts <d...@reply.com> wrote:  
> Patterns ARE central to solid development.

Patterns are like templates, they have become a trend
that everyone has to use, even there is no reason.
It's no wonder that programming has become non-productive,
generating programs that are buggy and slow. But I guess
programmers love complicated and fancy stuff. Maybe they
even get paid more to write more source code and spend
longer time doing that. Maybe patterns were invented just
because of that.

James Kanze

unread,
Sep 28, 2009, 4:13:38 AM9/28/09
to
On Sep 28, 2:37 am, "Chris M. Thomasson" <n...@spam.invalid> wrote:
> "Joshua Maurice" <joshuamaur...@gmail.com> wrote in message
[...]

> > Short version: Actually doing a correct singleton in C++ is
> > hard (tm).

> IMVHO, it sure as heck simplifies things if your program is
> single-threaded or you guarantee that no threads will ever be
> created before `main()'!!!

Yes. Except that you can extend it a little: you have to
guarantee that no threads which use the singleton will ever be
created before main. That's an important difference---when
third party libraries are involved, you can't make many
guarantees concerning what happens before main. (Sybase, for
example, does start threads from the constructors of static
objects, at least in some configurations.) On the other hand,
it's a pretty good bet that those libraries don't use a
singleton that you write.

--
James Kanze

James Kanze

unread,
Sep 28, 2009, 4:18:51 AM9/28/09
to
On Sep 28, 8:15 am, Krice <pau...@mbnet.fi> wrote:
> On 25 syys, 20:44, Noah Roberts <d...@reply.com> wrote:

> > Patterns ARE central to solid development.

> Patterns are like templates, they have become a trend
> that everyone has to use, even there is no reason.

Patterns are totally unlike templates; they aren't so much a
software development technique per se, as a means of
communication (including communicating with yourself). And
until someone suggests something better... Communication is
essential to well written programs, and using a recognized
pattern make the code far easier to understand (and thus more
likely correct) than it would be if you reinvented the wheel
each time around.

Note that in any real program, there will be lots of use of
patterns. I've never seen a GUI interface that didn't use at
least one of the template method pattern, the strategy pattern
or the decorator pattern. (Most will use all of them at
different points.) So the real question is: does the
documentation just say that such and such a pattern is used, or
does the documentation describe all of the nitty gritty details
each time, leaving the client wondering if somewhere in the
three or four pages of documentation, there isn't a subtle
difference in the pattern this time around.

--
James Kanze

Chris M. Thomasson

unread,
Sep 28, 2009, 8:31:43 PM9/28/09
to
"James Kanze" <james...@gmail.com> wrote in message
news:dcf6fb5f-3e7a-4938...@f10g2000vbf.googlegroups.com...

> On Sep 28, 2:37 am, "Chris M. Thomasson" <n...@spam.invalid> wrote:
>> "Joshua Maurice" <joshuamaur...@gmail.com> wrote in message
> [...]
>> > Short version: Actually doing a correct singleton in C++ is
>> > hard (tm).
>
>> IMVHO, it sure as heck simplifies things if your program is
>> single-threaded or you guarantee that no threads will ever be
>> created before `main()'!!!
>
> Yes. Except that you can extend it a little: you have to
> guarantee that no threads which use the singleton will ever be
> created before main. That's an important difference---when
> third party libraries are involved, you can't make many
> guarantees concerning what happens before main.

That is a very good point James.

Thanks.

Michael Doubez

unread,
Sep 29, 2009, 7:21:40 AM9/29/09
to
On 25 sep, 20:45, Joshua Maurice <joshuamaur...@gmail.com> wrote:
> On Sep 25, 1:05 am, Michael Doubez <michael.dou...@free.fr> wrote:
>
> > You can use a Meyer singleton which solve the initialisation order
> > issue:
>
> > static CSingleton& GetInstance()
> > {
> >  CSingleton static_instance;
>
> >  return static_instance;
>
> > }
>
> > And the cleanup is made at termination. The cleanup of a singleton is
> > delicate because you don't known how is currently using it (it is even
> > worse when in a DLL); you should let the system decide when it is no
> > longer needed.
>
> Suffice to say, actually suggesting the simplest Meyer's singleton is
> bad advice. Frankly, I've made so many mistakes on this topic recently
> that I'll just point you to the thread where someone more
> knowledgeable than me suggests more correct ways to do this.
>
> http://groups.google.com/group/comp.lang.c++/browse_thread/thread/bca...

>
> 1- Your singleton may cause static deinit issues. If you can leak it,
> just leak it. Otherwise, it'll work correctly if all other statics
> call getSingleton in their constructors. This will guarantee correct
> destruction order, Last In First Out.

You mean if a static gets latter on (after its initialisation) a
reference on the singleton ? This is not limited to singleton but to
every storage management; have seen some case where the singleton is
resetable causing that kind of problem but it is more related to the
logic of the program(er).

Betting on a singleton with the longest lifetime does guarantee your
program doesn't crash for this reason but it is IMHO at best a patch.

> 2- It's not thread-safe. There's the simple ways to do this correctly
> which come with the caveat that "No nontrivial threads during static
> init".

That is alas true. The next standard does provide atomic operations
which will ease that pain (I hope).

> Alternatively, use the more complex designs of Chris M.
> Thomasson, which just guarantee single correct construction with
> minimal overhead. There are several, depending on platform, and
> exactly what guarantees you want.

I have seen the code mentioned and it supposes that initialisation of
the mutex is atomic.

If I replace in the header:
typedef HANDLE pthread_mutex_t;
#define PTHREAD_MUTEX_INITIALIZER CreateMutex(/* params */)
You see the problem with:
static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;

In fact, it is possible that two mutex will be created and the mutex
is then useless.

In practice, IIRC it does work with the usual libpthread.

> Short version: Actually doing a correct singleton in C++ is hard (tm).

It is hard and not really useful in most cases.

Unless you are paid per "pattern-point". :)

--
Michael

Nick Keighley

unread,
Sep 29, 2009, 8:02:38 AM9/29/09
to

that's an unusual form of the singleton pattern. I've never seen
one where each user had to do a ReleaseInstance(). The GoF one doesn't

Chris M. Thomasson

unread,
Sep 29, 2009, 7:48:53 PM9/29/09
to
"Michael Doubez" <michael...@free.fr> wrote in message
news:5b98df17-4599-49bc...@k17g2000yqb.googlegroups.com...

On 25 sep, 20:45, Joshua Maurice <joshuamaur...@gmail.com> wrote:
[...]

> > Alternatively, use the more complex designs of Chris M.
> > Thomasson, which just guarantee single correct construction with
> > minimal overhead. There are several, depending on platform, and
> > exactly what guarantees you want.

> I have seen the code mentioned and it supposes that initialisation of
> the mutex is atomic.

> If I replace in the header:
> typedef HANDLE pthread_mutex_t;
> #define PTHREAD_MUTEX_INITIALIZER CreateMutex(/* params */)
> You see the problem with:
> static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;

> In fact, it is possible that two mutex will be created and the mutex
> is then useless.

> In practice, IIRC it does work with the usual libpthread.

Yes. The code I posted assumes that it will always be run under a POSIX
compliant platform. However, since you bring up Windows, well, there is a
hack one can use to dynamically and safely create a mutex in an atomic
fashion:
____________________________________________________________________
class win_dcl_mutex
{
HANDLE m_mutex;


private:
static std::string prv_get_name()
{
std::ostringstream name;

name << "DCL_MUTEX_" << GetCurrentProcessId();

return name.str();
}


public:
win_dcl_mutex() throw()
: m_mutex(CreateMutex(NULL, TRUE, prv_get_name().c_str()))
{
if (! m_mutex)
{
assert(m_mutex);
std::unexpected();
}

else if (GetLastError() == ERROR_ALREADY_EXISTS)
{
if (WaitForSingleObject(m_mutex, INFINITE) !=
WAIT_OBJECT_0)
{
assert(m_mutex);
CloseHandle(m_mutex);
std::unexpected();
}
}
}

~win_dcl_mutex() throw()
{
if (! ReleaseMutex(m_mutex))
{
assert(m_mutex);
CloseHandle(m_mutex);
std::unexpected();
}

if (! CloseHandle(m_mutex))
{
assert(m_mutex);
std::unexpected();
}
}
};
____________________________________________________________________


You would use this hack in the slow path of the DCL algorithm. You can make
this technique more fine grain by adding something to the constructor which
would further identify this mutex beyond using the current process id.
Something like:
____________________________________________________________________
class win_dcl_mutex
{
HANDLE m_mutex;


private:
template<typename T>
static std::string prv_get_name(T const& id)
{
std::ostringstream name;

name << "DCL_MUTEX_" << GetCurrentProcessId() << "_" << id;

return name.str();
}


public:
template<typename T>
win_dcl_mutex(T const& id) throw()
: m_mutex(CreateMutex(NULL, TRUE, prv_get_name(id).c_str()))
{
if (! m_mutex)
{
assert(m_mutex);
std::unexpected();
}

else if (GetLastError() == ERROR_ALREADY_EXISTS)
{
if (WaitForSingleObject(m_mutex, INFINITE) !=
WAIT_OBJECT_0)
{
assert(m_mutex);
CloseHandle(m_mutex);
std::unexpected();
}
}
}

~win_dcl_mutex() throw()
{
if (! ReleaseMutex(m_mutex))
{
assert(m_mutex);
CloseHandle(m_mutex);
std::unexpected();
}

if (! CloseHandle(m_mutex))
{
assert(m_mutex);
std::unexpected();
}
}
};
____________________________________________________________________


[...]

Joshua Maurice

unread,
Sep 29, 2009, 7:57:23 PM9/29/09
to
On Sep 29, 4:21 am, Michael Doubez <michael.dou...@free.fr> wrote:
> On 25 sep, 20:45, Joshua Maurice <joshuamaur...@gmail.com> wrote:
> > On Sep 25, 1:05 am, Michael Doubez <michael.dou...@free.fr> wrote:
> > > You can use a Meyer singleton which solve the initialisation order
> > > issue:
> > >
> > > static CSingleton& GetInstance()
> > > {
> > >  CSingleton static_instance;
> > >  return static_instance;
> > > }
> > >
> > > And the cleanup is made at termination. The cleanup of a singleton is
> > > delicate because you don't known how is currently using it (it is even
> > > worse when in a DLL); you should let the system decide when it is no
> > > longer needed.
> >
> > Suffice to say, actually suggesting the simplest Meyer's singleton is
> > bad advice. Frankly, I've made so many mistakes on this topic recently
> > that I'll just point you to the thread where someone more
> > knowledgeable than me suggests more correct ways to do this.
> >
> > http://groups.google.com/group/comp.lang.c++/browse_thread/thread/bca...
> >
> > 1- Your singleton may cause static deinit issues. If you can leak it,
> > just leak it. Otherwise, it'll work correctly if all other statics
> > call getSingleton in their constructors. This will guarantee correct
> > destruction order, Last In First Out.
>
> You mean if a static gets latter on (after its initialisation) a
> reference on the singleton ?

Yes.

> This is not limited to singleton but to
> every storage management; have seen some case where the singleton is
> resetable causing that kind of problem but it is more related to the
> logic of the program(er).
>
> Betting on a singleton with the longest lifetime does guarantee your
> program doesn't crash for this reason but it is IMHO at best a patch.

Agreed.

> > 2- It's not thread-safe. There's the simple ways to do this correctly
> > which come with the caveat that "No nontrivial threads during static
> > init".
>
> That is alas true. The next standard does provide atomic operations
> which will ease that pain (I hope).

IIRC: Even better: all initializors of namespace-scope variables and
static-local variables will have pthread_once semantics. It'll also
give basic atomic operations as well.

> > Alternatively, use the more complex designs of Chris M.
> > Thomasson, which just guarantee single correct construction with
> > minimal overhead. There are several, depending on platform, and
> > exactly what guarantees you want.
>
> I have seen the code mentioned and it supposes that initialisation of
> the mutex is atomic.
>
> If I replace in the header:
> typedef HANDLE pthread_mutex_t;
> #define PTHREAD_MUTEX_INITIALIZER CreateMutex(/* params */)
> You see the problem with:
> static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
>
> In fact, it is possible that two mutex will be created and the mutex
> is then useless.
>
> In practice, IIRC it does work with the usual libpthread.

I got this very wrong in the aforementioned thread. Chris does a good
job correcting me there. You are right that PTHREAD_MUTEX_INITIALIZER
has no (easy) windows equivalent. Check out the code Chris posted in
the aforementioned link. He covers this case as well.

Although, honestly, at this point I would just strongly suggest using
Boost's pthread_once wrapper, which basically uses Chris's windows
implementation for windows IIRC.

Michael Doubez

unread,
Sep 30, 2009, 3:54:23 AM9/30/09
to
On 30 sep, 01:48, "Chris M. Thomasson" <n...@spam.invalid> wrote:
> "Michael Doubez" <michael.dou...@free.fr> wrote in message

>
> news:5b98df17-4599-49bc...@k17g2000yqb.googlegroups.com...
> On 25 sep, 20:45, Joshua Maurice <joshuamaur...@gmail.com> wrote:
> [...]
>
> > > Alternatively, use the more complex designs of Chris M.
> > > Thomasson, which just guarantee single correct construction with
> > > minimal overhead. There are several, depending on platform, and
> > > exactly what guarantees you want.
> > I have seen the code mentioned and it supposes that initialisation of
> > the mutex is atomic.
> > If I replace in the header:
> > typedef HANDLE pthread_mutex_t;
> > #define PTHREAD_MUTEX_INITIALIZER CreateMutex(/* params */)
> > You see the problem with:
> > static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
> > In fact, it is possible that two mutex will be created and the mutex
> > is then useless.
> > In practice, IIRC it does work with the usual libpthread.
>
> Yes. The code I posted assumes that it will always be run under a POSIX
> compliant platform. However, since you bring up Windows, well, there is a
> hack one can use to dynamically and safely create a mutex in an atomic
> fashion:
>[snip]
>     :   m_mutex(CreateMutex(NULL, TRUE, prv_get_name().c_str()))
> [snip]

Yes, that solves the issue. It looks to me like creating a system wide
semaphore; well, not a worry really since the number of singleton
should be low.

--
Michael

Michael Doubez

unread,
Sep 30, 2009, 3:57:42 AM9/30/09
to
On 30 sep, 01:48, "Chris M. Thomasson" <n...@spam.invalid> wrote:
[snip]

>         if (! m_mutex)
>         {
>             assert(m_mutex);
>             std::unexpected();
>         }
[snip]

I wondered about this usage of assert() + unexpected(): what is the
rational of using both ?

To tell the truth, I never use std::unexpected(). How and when do you
use it ?

--
Michael

Chris M. Thomasson

unread,
Oct 2, 2009, 3:56:26 AM10/2/09
to
"Michael Doubez" <michael...@free.fr> wrote in message
news:c96a9e29-4305-446d...@v36g2000yqv.googlegroups.com...

On 30 sep, 01:48, "Chris M. Thomasson" <n...@spam.invalid> wrote:
[snip]
> > if (! m_mutex)
> > {
> > assert(m_mutex);
> > std::unexpected();
> > }
> [snip]

> I wondered about this usage of assert() + unexpected(): what is the
> rational of using both ?

I made several *mistakes in the "hard" error handling code. Sorry about
that.


> To tell the truth, I never use std::unexpected(). How and when do you
> use it ?

Quite frankly, I personally do not know which exception to throw as I am not
a C++ expert. I decorated the constructor/destructor and `prv_get_name()'
functions with the `throw()' clause. IMVHO, if the ctor of a singleton
fails, then end user program is in peril. Should the singleton ctor throw or
not?


(*)
BTW, here is corrected code:
_______________________________________________________________________
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <sstream>
#include <iostream>
#include <cstdio>


#if ! defined (WIN_DCL_MUTEX_UNEXPECTED)
# include <cassert>
# include <exception>
# define WIN_DCL_MUTEX_UNEXPECTED assert(false), std::unexpected
#endif


class win_dcl_mutex
{
HANDLE m_mutex;


private:
template<typename T>
static std::string prv_get_name(T const& id) throw()
{
std::ostringstream name;

name << "DCL_MUTEX_" << GetCurrentProcessId() << "_" << id;

// std::cout << name.str() << std::endl;

return name.str();
}


public:
template<typename T>
win_dcl_mutex(T const& id) throw()

: m_mutex(CreateMutex(NULL, TRUE, prv_get_name(id).c_str()))

{
if (! m_mutex)
{
WIN_DCL_MUTEX_UNEXPECTED();
}

else if (GetLastError() == ERROR_ALREADY_EXISTS)
{
if (WaitForSingleObject(m_mutex, INFINITE) !=
WAIT_OBJECT_0)
{

CloseHandle(m_mutex);
WIN_DCL_MUTEX_UNEXPECTED();
}
}
}

~win_dcl_mutex() throw()
{
if (! ReleaseMutex(m_mutex))
{

CloseHandle(m_mutex);
WIN_DCL_MUTEX_UNEXPECTED();
}

if (! CloseHandle(m_mutex))
{
WIN_DCL_MUTEX_UNEXPECTED();
}
}
};


int
main()
{
{
win_dcl_mutex mutex(12345);
}

return 0;
}

_______________________________________________________________________

Alf P. Steinbach

unread,
Oct 2, 2009, 5:12:29 AM10/2/09
to
* Chris M. Thomasson:

> "Michael Doubez" <michael...@free.fr> wrote in message
> news:c96a9e29-4305-446d...@v36g2000yqv.googlegroups.com...
> On 30 sep, 01:48, "Chris M. Thomasson" <n...@spam.invalid> wrote:
> [snip]
>> > if (! m_mutex)
>> > {
>> > assert(m_mutex);
>> > std::unexpected();
>> > }
>> [snip]
>
>> I wondered about this usage of assert() + unexpected(): what is the
>> rational of using both ?
>
> I made several *mistakes in the "hard" error handling code. Sorry about
> that.
>
>
>
>
>> To tell the truth, I never use std::unexpected(). How and when do you
>> use it ?
>
> Quite frankly, I personally do not know which exception to throw as I am
> not a C++ expert.

You can invoke std::terminate.

Or if you don't want a possible termination handler to execute, just abort().


> I decorated the constructor/destructor and
> `prv_get_name()' functions with the `throw()' clause. IMVHO, if the ctor
> of a singleton fails, then end user program is in peril. Should the
> singleton ctor throw or not?

Consider a singleton that represents a late-loaded (dynamically loaded) shared
library. In that case, if the library isn't present on the system then it might
be OK to continue with some fallback solution or reduced functionality. If that
singleton just aborts then it's rather difficult to continue...

But equally, there might be some singleton where the only sensible choice is to
abort no matter what, ensuring the same failure behavior in all cases (whether
the singleton is constructed from within a caller's code try-block or not).

So, I guess it's again Niels Bohr's statement, "The number of tails of a dog
depends on the dog".


Cheers,

- Alf

0 new messages