Re: question re. usage of "static" within static member functions of a class
"Joshua Maurice" <joshuamaurice@gmail.com> wrote in message
news:aac0ea5e-c259-4177-9781-d94931593069@j9g2000prh.googlegroups.com...
On Sep 9, 5:15 pm, "Chris M. Thomasson" <n...@spam.invalid> wrote:
[...]
You can get around static initialization and destruction ordering issues
by
using a strongly thread-safe smart pointer to manage the singleton. The
pseudo-code would be something like the following pseudo-code:
_____________________________________________________________________
[...]
_____________________________________________________________________
This is strongly thread-safe and will always work no matter how the
static
ctor/dtor ordering comes out. The caveat, well, it's definitely not as
efficient as using a raw pointer and explicitly leaking the singleton.
There are so many things wrong with that code sample, I don't even
know where to start. (Exaggeration. I do know where to start.)
Actually, well... How much experience do you have wrt multi-threading
issues?
Firstly and most importantly, you're using double checked locking,
which is broken in effectively all C++ implementations.
I explicitly stated that one can:
"get around static initialization and destruction ordering issues by using a
strongly thread-safe smart pointer to manage the singleton"
Do you have any idea what I am writing about here? Go ahead and put it on
the self because this discussion can get advanced rather quickly!
Don't do that.
;^)
Na. Anyway, double-checked locking IS 100% workable, period. You just don't
know it yet. That is NOT my problem. Oh well, shi% happens.
Please read, continue to re-read if you don't get it, this excellent
paper:
http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
What about it? Anyway, that paper is WELL known to me. Been there, done
that. Yawn.
Next, you also have a race condition on the construction of the mutex
itself,
;^/
Learn about POSIX:
http://www.opengroup.org/onlinepubs/7990989775/xsh/pthread_mutex_init.html
in addition to the double checked locking of the singleton
instance construction.
This is PERFECTLY fine. You just need to learn how to do it properly.
PTHREAD_MUTEX_INITIALIZER is entirely
equivalent to calling pthread_mutex_init, and thus is not thread-safe.
:^O
Learn about POSIX:
http://www.opengroup.org/onlinepubs/7990989775/xsh/pthread_mutex_init.html
Repeat:
lptr.reset(new T());
is not properly guarded (double checked locking) and
Yawn.
static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
is not properly guarded (simple race condition). Both are race
conditions when the first call of this function may be concurrent.
I am getting tired.
Also, users may want multiple singletons of the same type. One unit of
code makes a singleton of type T, and another piece of code entirely
separate will make another singleton of type T. Your code does not
support that. Instead, you will get exactly 1 instance of T across the
entire program. This is a significant limitation.
FINALLY! You actually make sense; congratulations!
:^D
You could
potentially get it around it with something like:
//header code
template <typename singleton_t, typename once_type>
singleton_t & getSingleton();
//code using the header to make a singeton in a hpp
class singleton_x_type { /* ... */ };
class once_type_for_singleton_X {};
singleton_x_type & getSingletonX()
{
return getSingleton<singleton_x_type, once_type_for_singleton_X>
();
}
If another piece of code wanted their own singleton of type X, then
they could define their own once_type and instantiate getSingleton on
that new once_type.
Sure.
Lastly, RAII is your friend. Don't ever explicitly call
pthread_mutex_lock or pthread_mutex_unlock except in your portability
layer mutex wrapper class.
Sure. Although, using try/catch is 100% perfectly fine. Whatever, this was
pseudo-code; lol. Anyway, here is example of RAII:
http://groups.google.com/group/comp.lang.c++/msg/63c3aecb9d0fbaa6
Blah, blah.
This is not a correctness issue per se, but
vastly improves the chances that the code will be correct.
Yes; RAII is very convenient.
Your solution could be made correct by eager initializing it by adding
namespace { bool force_init = (::once<your_type>(), true); }
My pseudo-code IS correct. IMVHO, you obviously need some education, that's
all; there is absolutely NOTHING to be ashamed about. I personally LOVE to
earn __all__ about new things!!!
However, at that point, your fixed code is pretty much equivalent to
several examples already posted, aka:
T& getSingleton()
{ static T* x = new T;
return *x;
}
namespace { bool force_init = (getSingleton(), true); }
NO!
;^/