Initialization of local statics

M

Marcel Müller

Hi,

the following code

#include <stdio.h>

struct A
{ A() { puts("A()"); }
~A() { puts("~A()"); }
};

static const A& foo()
{ puts("foo()");
static const A var;
return var;
}

int main()
{
puts("main()");
foo();
foo();
return 0;
}

prints

main()
foo()
A()
foo()
~A()

So var inside foo is initialized after the first pass of the code over
the variable definition. Well, that would be useful in conjunction with
templates to achieve late initialization and avoid static initialization
dependencies.
But is this execution order guaranteed? (I guess yes.) And if so, what
does this mean with respect to threads?
If this is not thread safe one could never store non POD constants in
local statics in a multi threaded application, even if the underlying
object type provides thread safety for const methods, isn't it?


Marcel
 
J

Juha Nieminen

Marcel Müller said:
But is this execution order guaranteed? (I guess yes.)

AFAIK, yes. It can sometimes be a handy trick for executing code lazily
only when needed (code which has to be executed only once, of course),
without having to explicitly put a boolean somewhere to see if the code
has already been executed or not, for example:

void foo()
{
static SomeClass someObject = someReallyExpensiveFunction();
...
}
And if so, what
does this mean with respect to threads?

AFAIK the current standard takes no stance on thread-safety on anything
(I'm not even sure it does so even for malloc()/new, even though in
practical implementations those always are). Hence I don't think the
standard guarantees thread-safety for initializing local statics either.
(In other words, if two threads call the function simultaneously, the
initialization of the static object might get screwed up, unless the
compiler itself guarantees mutual exclusion.)
 
M

Marcel Müller

Juha said:
AFAIK the current standard takes no stance on thread-safety on anything
(I'm not even sure it does so even for malloc()/new, even though in
practical implementations those always are). Hence I don't think the
standard guarantees thread-safety for initializing local statics either.
(In other words, if two threads call the function simultaneously, the
initialization of the static object might get screwed up, unless the
compiler itself guarantees mutual exclusion.)

Just decompiled the binary. You are right, at least gcc 3.3.5 makes
absolutely no protection around the flag.

Maybe because it might be quite expensive, since other threads must be
blocked during the initialization. Of course, the runtime overhead on
each evaluation can be close to zero by using a double check. But we
still need a synchronization resource for each static object. This is
most likely the major drawback.


Marcel
 
A

Anthony Williams

Marcel Müller said:
But is this execution order guaranteed? (I guess yes.) And if so, what
does this mean with respect to threads?

The C++03 standard doesn't say anything about threads at all, and so any
compiler that supports threads can do whatever it likes. gcc has a
compiler flag that selects whether or not such initialization is
thread-safe, for example.

The upcoming C++0x standard requires that the initialization of
local-statics is thread-safe.

Anthony
 
M

Marcel Müller

Anthony said:
The upcoming C++0x standard requires that the initialization of
local-statics is thread-safe.

Ah! Nice to know.
Even though I can't wait for this.


Marcel
 
M

Marcel Müller

Paavo said:
static const A& foo()
{ puts("foo()");
static const A var;
return var;
} [...]
If this is not thread safe one could never store non POD constants in
local statics in a multi threaded application, even if the underlying
object type provides thread safety for const methods, isn't it?

For making this thread-safe there is a simple approach not involving any
locking: just make sure that any such function is called at least once in
the beginning of main(), before any extra threads are created. This
assumes of course that no threads are created directly or indirectly
from constructors of static objects.

Well, it might be not that simple to call a member function deep in the
business logic without even having an object of the appropriate type.
Furthermore if there is no need for delayed initialization, you could
simply move the static object outside the method implementation in the
compilation unit to achieve the same automatically. But then we are
talking about the static initialization hell.
Note that there is a similar rule for program shutdown: one should take
care that all created threads are properly joined before program exit, so
the statics are destroyed in single-threaded mode.

Never heard of that. But of course, it is straight forward to do so.
Calling exit() with several active threads makes no sense anyway.
Depending on the platform the result is completely different. WinXX
AFAIK ends the application not before the last thread died. OS/2
implicitly cancels all threads unconditional if thread 1 dies.


Marcel
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top