C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Thread-safe initialization of a function static
Goto page 1, 2, 3, 4, 5  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Scott Meyers
Guest





PostPosted: Mon Apr 19, 2004 9:50 am    Post subject: Thread-safe initialization of a function static Reply with quote



Consider a function-static object:

void f() {
...
static T someObj; // call T ctor
...
}

At the point where the static is defined, it seems clear that compilers
have to generate code that more or less boils down to this:

if (someObj isn't initialized) {
initialize someObj
note that someObj is initialized;
}

This isn't thread-safe, because two threads could perform the
initialization at the same time.

An obvious way to try to address this is to wrap the static's definition in
a critical section:

void f() {
...
begin_critical_section();
static T someObj;
end_critical_section();
...
}

In "Pattern Hatching," John Vlissides quotes Erich Gamma as saying that
it's not possible to make function-static initialization thread-safe
(pg. 70), so presumably the above isn't guaranteed to work. I've known
this since the book came out in 1997, but for the first time, I find myself
wondering why. Can somebody please explain to me why putting the
definition and initialization of a function static in a critical section
isn't a reliable way to make it thread-safe?

Thanks,

Scott

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Antoun Kanawati
Guest





PostPosted: Tue Apr 20, 2004 10:15 am    Post subject: Re: Thread-safe initialization of a function static Reply with quote



Scott Meyers wrote:

Quote:
Consider a function-static object:

void f() {
...
static T someObj; // call T ctor
...
}

At the point where the static is defined, it seems clear that compilers
have to generate code that more or less boils down to this:

if (someObj isn't initialized) {
initialize someObj
note that someObj is initialized;
}

This isn't thread-safe, because two threads could perform the
initialization at the same time.

An obvious way to try to address this is to wrap the static's definition in
a critical section:

void f() {
...
begin_critical_section();
static T someObj;
end_critical_section();
...
}

In "Pattern Hatching," John Vlissides quotes Erich Gamma as saying that
it's not possible to make function-static initialization thread-safe
(pg. 70), so presumably the above isn't guaranteed to work. I've known
this since the book came out in 1997, but for the first time, I find myself
wondering why. Can somebody please explain to me why putting the
definition and initialization of a function static in a critical section
isn't a reliable way to make it thread-safe?

If the static object uses other static objects which are also protected
with critical sections, and you have multiple threads trying to
initialize static objects, can you insure that you will not get any
cycles? and can you insure that all static initializations are using
critical sections?

There are techniques to work around this: before starting any threads,
make sure that all static initializers have run, by invoking these
special functions, whether you need them or not. This means that
the function statics have to live in environments like this:

foo &getTheFoo() {
static foo thefoo(....);
return thefoo;
}

otherwise, you won't be able to invoke them for mere initialization.

Then, there is other people's code (third party libraries). Hopefully,
all their statics are threadsafe too, they don't start threads that
they don't tell you about, etc...

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Dhruv Matani
Guest





PostPosted: Tue Apr 20, 2004 10:25 am    Post subject: Re: Thread-safe initialization of a function static Reply with quote



On Mon, 19 Apr 2004 05:50:48 -0400, Scott Meyers wrote:

Quote:
Consider a function-static object:

void f() {
...
static T someObj; // call T ctor
...
}

At the point where the static is defined, it seems clear that compilers
have to generate code that more or less boils down to this:

if (someObj isn't initialized) {
initialize someObj
note that someObj is initialized;
}

Why can't it generate code like this:

0: function <Function_Name>
1: //Set up stack frame.
2: jmp 3
3: //Initialize local static.
4: change the value '3' in statement 2 above to '5' (in memory!).
5: //Actual function code.
6. //Restore esp.
7. return.

I haven't seen self modify code for quite some time now! Apparently, it
confuses the processor branch predection algorithm!

--
Regards,
-Dhruv.

Proud to be a Vegetarian.
http://www.vegetarianstarterkit.com/
http://www.vegkids.com/vegkids/index.html


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Gerhard Menzl
Guest





PostPosted: Tue Apr 20, 2004 10:27 am    Post subject: Re: Thread-safe initialization of a function static Reply with quote

Scott Meyers wrote:

Quote:
void f() {
...
begin_critical_section();
static T someObj;
end_critical_section();
...
}

In "Pattern Hatching," John Vlissides quotes Erich Gamma as saying that
it's not possible to make function-static initialization thread-safe
(pg. 70), so presumably the above isn't guaranteed to work. I've known
this since the book came out in 1997, but for the first time, I find myself
wondering why. Can somebody please explain to me why putting the
definition and initialization of a function static in a critical section
isn't a reliable way to make it thread-safe?

I find it astonishing that you among all participants should really have
missed all those endless threadsafe singleton debates that have raged in
this newsgroup. You must have been very busy working on "Effective STL". :-)

As I remember the discussion, the gist was that the compiler, which is
fully entitled to ignore threading issues, might place the object
creation test, which is an implementation detail of code generation
after all, *before* begin_critical_section(), thus thwarting the
laudable intent of the programmer.

Gerhard Menzl
--
Humans may reply by replacing the obviously faked part of my e-mail
address with "kapsch".

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Anthony Smith
Guest





PostPosted: Tue Apr 20, 2004 7:26 pm    Post subject: Re: Thread-safe initialization of a function static Reply with quote

Hi

It seems that the main problem here is when the initialization takes place.
Although at face value the static data member only appears for the first
time after the start of the critical section, this may well not be the case
in compiled code. The Standard says (6.7 para. 4) "A local object of POD
type with static storage duration initilized with constant-expressions is
initialised before it's block is first entered." So essentially
initilisation in this case would happen before our critical section control
code is ever encountered. It gets worse with the next sentence, "An
implementation is permitted to perform early initialization of other local
objects with static storage duration under the same conditions that an
implementation is permitted to statically initialize an object with static
storage duration in namespace scope". Now static objects in namespace scope
may pretty much be initialised at any time starting before the first
statement of main() is executed up to the time just before the static object
is first used.(specified in 3.6.2 para 3) as this is left to be
implementation defined. So I infer from that that if we have

void f() {
...
begin_critical_section();
static T someObj;
end_critical_section();
...
}

then our "someObj" may, depending on the implementation of the compiler,
have it's constructor called at any time between entering the scope of f(),
and the point of it's declaration. In fact, I couldn't find anything in the
Standard that said a compiler can't initialize any function's local static
objects even before the first statement of main() is called. Not satisfied
I then looked at the compiled code in the disassembler with varying levels
of optimization and what I saw confirmed my suspicions.

Hope this helps

Anthony Smith

"Scott Meyers" <Usenet (AT) aristeia (DOT) com> wrote

Quote:
Consider a function-static object:

void f() {
...
static T someObj; // call T ctor
...
}

At the point where the static is defined, it seems clear that
compilers have to generate code that more or less boils down to this:

if (someObj isn't initialized) {
initialize someObj
note that someObj is initialized;
}

This isn't thread-safe, because two threads could perform the
initialization at the same time.

An obvious way to try to address this is to wrap the static's
definition
in
a critical section:

void f() {
...
begin_critical_section();
static T someObj;
end_critical_section();
...
}

In "Pattern Hatching," John Vlissides quotes Erich Gamma as saying
that it's not possible to make function-static initialization
thread-safe (pg. 70), so presumably the above isn't guaranteed to
work. I've known this since the book came out in 1997, but for the
first time, I find
myself
wondering why. Can somebody please explain to me why putting the
definition and initialization of a function static in a critical
section isn't a reliable way to make it thread-safe?

Thanks,

Scott

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
apm
Guest





PostPosted: Tue Apr 20, 2004 7:38 pm    Post subject: Re: Thread-safe initialization of a function static Reply with quote

Scott Meyers <Usenet (AT) aristeia (DOT) com> wrote in message > At the point
where the static is defined, it seems clear that compilers
Quote:
have to generate code that more or less boils down to this:

if (someObj isn't initialized) {
initialize someObj
note that someObj is initialized;
}

This isn't thread-safe, because two threads could perform the
initialization at the same time.

Agreed but it doesn't matter if someObj is a POD apart from
a slight inefficiency. For non-PODs the work in the ctor
may get duplicated of course, with potentially disastrous results.

Quote:

An obvious way to try to address this is to wrap the static's
definition in
a critical section:
[snip]
In "Pattern Hatching," John Vlissides quotes Erich Gamma as saying that
it's not possible to make function-static initialization thread-safe
(pg. 70), so presumably the above isn't guaranteed to work. I've known
this since the book came out in 1997, but for the first time, I find
myself
wondering why.
I think it is so I find this suprising.

What is not guaranteed is that the snipped code is portable.

Quote:
Can somebody please explain to me why putting the
definition and initialization of a function static in a critical
section
isn't a reliable way to make it thread-safe?

I must admit I always thought it was, although the facilities
to take and release the region are OS-specific and may even
require some assembler to avoid cache coherency problems
on multi-CPU architectures.

Regards,

Andrew Marlow

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Pete Becker
Guest





PostPosted: Tue Apr 20, 2004 7:43 pm    Post subject: Re: Thread-safe initialization of a function static Reply with quote

Scott Meyers wrote:
Quote:

An obvious way to try to address this is to wrap the static's
definition in a critical section:

void f() {
...
begin_critical_section();
static T someObj;
end_critical_section();
...
}

In "Pattern Hatching," John Vlissides quotes Erich Gamma as saying
that it's not possible to make function-static initialization
thread-safe (pg. 70), so presumably the above isn't guaranteed to
work. I've known this since the book came out in 1997, but for the
first time, I find myself wondering why. Can somebody please explain
to me why putting the definition and initialization of a function
static in a critical section isn't a reliable way to make it thread-safe?


The person to ask is whoever said it. Of course, the functions
'begin_critical_section' and 'end_critical_section' here have rather thin
specifications, so it's hard to guess at what problems they might have. But
in general, if begin_critical_section locks a mutex and end_critical_section
unlocks it (and assuming that someObj's constructor doesn't throw
exceptions) this ought to work.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Mogens Hansen
Guest





PostPosted: Tue Apr 20, 2004 9:45 pm    Post subject: Re: Thread-safe initialization of a function static Reply with quote



"Scott Meyers" <Usenet (AT) aristeia (DOT) com> wrote:

[8<8<8<]
Quote:
An obvious way to try to address this is to wrap the static's
definition in a critical section:

void f() {
...
begin_critical_section();
static T someObj;
end_critical_section();
...
}

In "Pattern Hatching," John Vlissides quotes Erich Gamma as saying
that it's not possible to make function-static initialization
thread-safe (pg. 70), so presumably the above isn't guaranteed to
work. I've known this since the book came out in 1997, but for the
first time, I find myself wondering why. Can somebody please explain
to me why putting the definition and initialization of a function
static in a critical section isn't a reliable way to make it
thread-safe?

I fail to see that it shouldn't be reliable.
However, since the C++ specification doesn't deal with multi-threading
at all, it may be fair to say that it is not guaranteed to work.

If there only is a race-condition during construction of "someObj", then
this solution may impose a significant locking overhead.

See Douglas C. Schmidt and Tim Harrison's paper on the design pattern
"Double-Checked Locking"
(http://www.cs.wustl.edu/~schmidt/PDF/DC-Locking.pdf) for a solution to
this problem.

Kind regards

Mogens Hansen



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Maciej Sobczak
Guest





PostPosted: Tue Apr 20, 2004 9:46 pm    Post subject: Re: Thread-safe initialization of a function static Reply with quote

Hi,

Scott Meyers wrote:

Quote:
Consider a function-static object:
[...]
void f() {
...
begin_critical_section();
static T someObj;
end_critical_section();
...
}

In "Pattern Hatching," John Vlissides quotes Erich Gamma as saying that
it's not possible to make function-static initialization thread-safe
(pg. 70), so presumably the above isn't guaranteed to work. I've known
this since the book came out in 1997, but for the first time, I find myself
wondering why.

Just a guess.
Initialization of local static variable can require that there is some
additional flag that controls it. The fact that this flag is implicit
and implementation-provided means that you have no control over when its
value is read. The flag is not explicit, so it cannot be bound by the
usual thoery of sequence points and so on, meaning that the compiler is
free to do whatever it wants with it, like here:

void f()
{
// compiler does this:
auto bool isInitialized = __Get__The__Flag__();

...

// your code:
begin_critical_section();

// your code:
// static T someObj;
// compiler does this instead:
if (isInitialized == false)
{
__Initialize__(someObj); // BANG!
__Set__The__Flag__(true);
}

// your code:
end_critical_section();

...
}

The use of "auto" and excessive double underscores is meant to stress
the problem.

The solution I use is to have static objects wrapped in separate
functions (mini-singletons), like here:

T & theObject()
{
static T someObj;
return someObj;
}

and later refer to someObj through theObject() accessor.
I call theObject() for every static I need *before* I start the threads
that are using it, just to enforce their construction.
I know that this way I loose the possibility of lazy construction, but
it can be achieved by messing (sorry: mixing) these two approaches:

T & theObject() { static T obj; return obj; }

void f()
{
begin_critical_section();
T & obj = theObject();
end_critical_section();

...
// use obj
}

I assume that the whole compiler's magic is encapsulated inside
theObject() function, which allows me to treat it as a single action.

--
Maciej Sobczak : http://www.msobczak.com/
Programming : http://www.msobczak.com/prog/


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Wil Evers
Guest





PostPosted: Tue Apr 20, 2004 9:48 pm    Post subject: Re: Thread-safe initialization of a function static Reply with quote

In article <MPG.1aed0b19e963718398973d (AT) news (DOT) hevanet.com>, Scott Meyers
wrote:

Quote:
Consider a function-static object:

void f() {
...
static T someObj; // call T ctor
...
}

At the point where the static is defined, it seems clear that compilers
have to generate code that more or less boils down to this:

if (someObj isn't initialized) {
initialize someObj
note that someObj is initialized;
}

It seems to me you forgot something - at least when T has a destructor:

if (someObj isn't initialized) {
initialize someObj
===> register destruction of someObj at program exit
note that someObj is initialized
}

Quote:
This isn't thread-safe, because two threads could perform the
initialization at the same time.

An obvious way to try to address this is to wrap the static's definition
in a critical section:

void f() {
...
begin_critical_section();
static T someObj;
end_critical_section();
...
}

In "Pattern Hatching," John Vlissides quotes Erich Gamma as saying that
it's not possible to make function-static initialization thread-safe
(pg. 70), so presumably the above isn't guaranteed to work. I've known
this since the book came out in 1997, but for the first time, I find
myself
wondering why. Can somebody please explain to me why putting the
definition and initialization of a function static in a critical section
isn't a reliable way to make it thread-safe?

Well, as we all know, the standard has nothing to say about threads,
although that is about to change. In the meantime, we'll have to live with
the design decisions made by various compiler implementors. As an interim
solution, I think your idea should work, but only if

(1) We ignore the possibility of exceptions escaping from someObj's
constructor.
(2) The mechanism used to register the call to someObj's destructor at
program exit is thread-safe.

I can think of various workarounds for (1). (2) is much harder to deal with,
because it is normally not under the user's control.

[ Data point: on my system (Linux, gcc-3.3.3, glibc-2.3.3), the flag byte
that is used to register someObj's construction is not protected by any
sort of lock, but the atexit registry is. ]

However, I suppose that when multi-threading is included in the standard,
and if the relevant sections about the dynamic initialization of local
statics aren't changed, we'll end up in a situation where conforming
implementations are pretty much required to take care of all the details
and simply get it right.

Regards,

- Wil

--
Wil Evers, DOOSYS R&D BV, Utrecht, Holland
[Wil underscore Evers at doosys dot com]


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Rob
Guest





PostPosted: Tue Apr 20, 2004 10:23 pm    Post subject: Re: Thread-safe initialization of a function static Reply with quote

"Scott Meyers" <Usenet (AT) aristeia (DOT) com> wrote

Quote:
[Snip]
"Pattern Hatching," John Vlissides quotes Erich Gamma as saying that
it's not possible to make function-static initialization thread-safe
(pg. 70), so presumably the above isn't guaranteed to work. I've known
this since the book came out in 1997, but for the first time, I find
myself
wondering why. Can somebody please explain to me why putting the
definition and initialization of a function static in a critical section
isn't a reliable way to make it thread-safe?


I would assume because it's necessary to create and initialise the critical
section. A critical section is an object that needs to be initialised
like any other. In this case, it would need to be initialised before
the function static, so the critical section is effectively another static
object that requires initialisation.

I would, however, dispute the claim that it's not possible to make
function initialisation thread safe. It would be possible for the
*compiler implementation* to provide appropriate guarantees,
by (for example) initialising an appropriate critical section in
startup code that the implementation guarantees is called before
anything else, and then implicitly entering that critical section when
a statics are required to be initialised. That would imply a performance
hit for applications built using that compiler though.

I would agree it is not possible for the humble C++ programmer to
make function static initialisation thread-safe without compiler support.





[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Randy Maddox
Guest





PostPosted: Tue Apr 20, 2004 11:23 pm    Post subject: Re: Thread-safe initialization of a function static Reply with quote

"Dhruv Matani" <dhruvbird (AT) gmx (DOT) net> wrote

Quote:


[snip]

Quote:
I haven't seen self modify code for quite some time now! Apparently, it
confuses the processor branch predection algorithm!

--
Regards,
-Dhruv.


Possibly because it is evil, but more likely because most executable
code resides nowadays in non-writable pages in memory for safety.

Randy.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Dhruv Matani
Guest





PostPosted: Tue Apr 20, 2004 11:31 pm    Post subject: Re: Thread-safe initialization of a function static Reply with quote

On Tue, 20 Apr 2004 06:27:29 -0400, Gerhard Menzl wrote:

Quote:
Scott Meyers wrote:

void f() {
...
begin_critical_section();
static T someObj;
end_critical_section();
...
}

In "Pattern Hatching," John Vlissides quotes Erich Gamma as saying that
it's not possible to make function-static initialization thread-safe
(pg. 70), so presumably the above isn't guaranteed to work. I've known
this since the book came out in 1997, but for the first time, I find myself
wondering why. Can somebody please explain to me why putting the
definition and initialization of a function static in a critical section
isn't a reliable way to make it thread-safe?

I find it astonishing that you among all participants should really have
missed all those endless threadsafe singleton debates that have raged in
this newsgroup. You must have been very busy working on "Effective STL". :-)

As I remember the discussion, the gist was that the compiler, which is
fully entitled to ignore threading issues, might place the object
creation test, which is an implementation detail of code generation
after all, *before* begin_critical_section(), thus thwarting the
laudable intent of the programmer.

Why should the compiler ever do that?

Consider:

void foo()
{
int x = 3;
static int y = 6;
}

Are you saying that the code generated would look like:

bool Global_Init_y = false;
int y;

foo:
if (!Global_Init_y)
//Increment ebp.
x = 3;
y = 6;
endif;
end_foo;


--
Regards,
-Dhruv.

Proud to be a Vegetarian.
http://www.vegetarianstarterkit.com/
http://www.vegkids.com/vegkids/index.html


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Antoun Kanawati
Guest





PostPosted: Tue Apr 20, 2004 11:35 pm    Post subject: Re: Thread-safe initialization of a function static Reply with quote

Gerhard Menzl wrote:

Quote:
Scott Meyers wrote:

void f() {
...
begin_critical_section();
static T someObj;
end_critical_section();
...
}
...
As I remember the discussion, the gist was that the compiler, which is
fully entitled to ignore threading issues, might place the object
creation test, which is an implementation detail of code generation
after all, *before* begin_critical_section(), thus thwarting the
laudable intent of the programmer.

Moving the initialization before begin_critical_section() would be
wrong, regardless of threading. What if the function throws or never
returns? Even worse, what if the constructor throws up? the critical
section is locked forever.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Pete Becker
Guest





PostPosted: Wed Apr 21, 2004 12:14 am    Post subject: Re: Thread-safe initialization of a function static Reply with quote

apm wrote:
Quote:

Scott Meyers <Usenet (AT) aristeia (DOT) com> wrote in message > At the point
where the static is defined, it seems clear that compilers
have to generate code that more or less boils down to this:

if (someObj isn't initialized) {
initialize someObj
note that someObj is initialized;
}

This isn't thread-safe, because two threads could perform the
initialization at the same time.

Agreed but it doesn't matter if someObj is a POD apart from
a slight inefficiency.

It does matter. Suppose the first thread, after initializing someObj,
modifies it. The second initialization overwrite this change.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Goto page 1, 2, 3, 4, 5  Next
Page 1 of 5

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.