Re: Threadsafe singletons
kanze wrote:
David Barrett-Lennard wrote:
kanze wrote:
David Barrett-Lennard wrote:
kanze wrote:
David Barrett-Lennard wrote:
[...]
At least some compilers, in a threaded environment, use
something like pthread_once to initialize the variable, so
constructing it before entering main isn't necessary.
Good point. I didn't know some compilers would do that.
Only some. In my opinion, it should be required, once the
C++ standard recognizes threads, but there are valid
arguments both ways: a function with a static variable is
inherently not thread safe, and presumably will be used only
in a single threaded environment, or when the client code
has provided higher level protection. In such cases, there
is no threading issue in the code, and the use of something
like pthread_once is extra overhead---you're paying for
something you don't use. (But I'm still in favor of doing
the right thing.)
I think the compiler should keep out of such concerns!
Particularly now that most compilers don't give thread safety.
The last compiler I used that didn't guarantee thread safety was
g++ 2.95.2. If a compiler doesn't guarantee thread safety, you
can't use it for multithreaded code. It's as simple as that.
How do you know that it doesn't use static variables internally?
AFAIK VC++ never (silently) adds synchronization primitives to your
code.
Can you give me an example of where a compiler introduces an unexpected
static?
If I can write:
void
f()
{
static int const i = 42 ;
// ...
}
and expect it to work
Why expect that to be threadsafe? The compiler isn't required to
optimize the variable out of existence is it? Assuming it initializes
it on first access, you should expect a potential racing condition.
Furthermore, even if you ensure one thread calls f() before any other
threads, you will need to ensure memory barriers are used
appropriately.
As I see it, global variables or static variables inside functions
*always* indicate potential thread-safety problems, and I don't
expect the compiler to do anything about that. This keeps the compiler
and language simple, and makes it easier to maximize performance.
I should also be able to write:
void
f()
{
static std::string const s = "42" ;
// ...
}
Where's the logical difference?
The cat's out of the bag!
It is already.
My own technique is basically:
static MySingleton* ourInstance = &MySingleton::instance() ;
MySingleton&
MySingleton::instance()
{
if ( ourInstance == NULL ) {
ourInstance = new MySingleton ;
}
return *ourInstance ;
}
How is it deleted?
It isn't. Generally, I don't want it to be; deleting it leads
to problems in the ordering of destructors (supposing it is used
in the destructor of an object with static lifetime).
I have never had an order of destruction problem myself.
You've never had one, or you've never had one that hadn't been
solved by someone else already. Have you ever used std::cerr in
the destructor of a static object? How do you know that it
hadn't been destructed already? The standard has taken special
precautions to ensure that it will not be destructed.
However I use singletons rarely and they tend to be used
either for caching or for registries. Can you outline a
reasonable example with order of destruction problems?
A singleton log? I can imagine wanting to log in a destructor.
But your singleton destructors never run!
As a general rule my programs only do observable things within the
scope of main(). Threads, files, sockets, windows etc are only opened
and closed within the scope of main(). Therefore I don't do anything
important in singleton destructors. You evidently don't either
because you don't destruct them at all.
I use assertions to trap attempts to log messages after the log file
has been explicitly closed from main(), unless the log file is a
debugging aid for the programmer. In the latter case it logically
needs to outlive the scope of main(). Only in that case would I
consider allowing the singleton to leak and assume the system closes
the log file for me.
I find it convenient to know that my programs (should) never have any
memory leaks. VC++ can dump all the leaks in the output pane. It's
nice for this to be empty unless there is a programming error.
Cheers,
David Barrett-Lennard
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]