
I need to ensure that certain objects (specifically the policy bundles which manage singleton instances) are created in a thread-safe manner. First question: Can two threads both initialize the same static variable if they pass through the same function at the same time? Ex: void foo ( ) { static Thing t; } Can t's constructor be called twice by two threads executing foo? If so, I feel that I need to construct my policy bundles before execution enters main, a time when it is pretty much guaranteed that the application is operating in a single-threaded context. I thought that this would be simple to do: just write a class that calls the function with the static variable in its constructor and create a global instance of that class. However, the standard appears to say that initialization of such global variables can happen after main is entered, so long as it happens before the global variable is used. If the program starts spawning threads before the global variable is constructed I would still have the same problem. How can I ensure that initialization is performed before main is entered? If I cannot, is there some other way to make initialization of static variables thread-safe? I cannot lock a mutex to manage this, because the mutex lives inside the threading policy instance and the threading policy instance lives in the policy bundle that I am trying to create in the first place. -Jason

Jason Hise wrote:
How can I ensure that initialization is performed before main is entered? If I cannot, is there some other way to make initialization of static variables thread-safe? I cannot lock a mutex to manage this, because the mutex lives inside the threading policy instance and the threading policy instance lives in the policy bundle that I am trying to create in the first place.
You might want to look at this thread: http://tinyurl.com/9xe83 Jonathan

Jonathan Turkanis wrote:
Jason Hise wrote:
How can I ensure that initialization is performed before main is entered? If I cannot, is there some other way to make initialization of static variables thread-safe? I cannot lock a mutex to manage this, because the mutex lives inside the threading policy instance and the threading policy instance lives in the policy bundle that I am trying to create in the first place.
You might want to look at this thread:
Jonathan
That does indeed confirm that function-local statics are not initialized in a thread-safe manner on some current popular C++ compilers. So to avoid the whole mess regarding the DCLP, the best approach would probably be eager initialization, before the program enters a multi-threaded context. Is initializing from the constructor of a namespace-scope global enough to ensure this? -Jason

Jason Hise wrote:
Jonathan Turkanis wrote:
You might want to look at this thread:
Jonathan
That does indeed confirm that function-local statics are not initialized in a thread-safe manner on some current popular C++ compilers. So to avoid the whole mess regarding the DCLP, the best approach would probably be eager initialization, before the program enters a multi-threaded context. Is initializing from the constructor of a namespace-scope global enough to ensure this?
I don't think so, since you might want to access singletons from static initializers in other translation units. Have you considered using call_once: http://www.boost.org/doc/html/call_once.html? It might look like this: boost::once_flag foo_once = BOOST_ONCE_INIT; Thing* t = 0; void foo_init() { t = new Thing; } void foo() { boost::call_once(&foo_init, foo_once); // Use *t } I'm not sure this will work, so check it with someone else.
-Jason
Jonathan

Jonathan Turkanis wrote:
Jason Hise wrote:
So to avoid the whole mess regarding the DCLP, the best approach would probably be eager initialization, before the program enters a multi-threaded context. Is initializing from the constructor of a namespace-scope global enough to ensure this?
I don't think so, since you might want to access singletons from static initializers in other translation units.
Have you considered using call_once: http://www.boost.org/doc/html/call_once.html?
Why does it require that the function which is called once not be allowed to throw? I am not sure that I can meet this requirement, as I may need to dynamically allocate memory. -Jason

Jason Hise wrote:
Jonathan Turkanis wrote:
Jason Hise wrote:
So to avoid the whole mess regarding the DCLP, the best approach would probably be eager initialization, before the program enters a multi-threaded context. Is initializing from the constructor of a namespace-scope global enough to ensure this?
I don't think so, since you might want to access singletons from static initializers in other translation units.
Have you considered using call_once: http://www.boost.org/doc/html/call_once.html?
Why does it require that the function which is called once not be allowed to throw? I am not sure that I can meet this requirement, as I may need to dynamically allocate memory.
Whoops! I forgot about that. In the example I gave, you can use boost::optional. If the construction of your object can throw, I think you can use the above method to construct a mutex (in a buffer using placement new) and use the mutex to synchronize construction of the object. Jonathan

Have you considered using call_once: http://www.boost.org/doc/html/call_once.html?
If thread A enters call_once, and then thread B enters call_once before
Jonathan Turkanis wrote: thread A exits, will thread B block waiting for A to finish or will it just return immediately? -Jason

"Jason Hise" wrote:
Why does it require that the function which is called once not be allowed to throw? I am not sure that I can meet this requirement, as I may need to dynamically allocate memory.
Possibly because of internal implementation. If the function throws next time the call_once will be executed again (likely a bug). /Pavel

Pavel Vozenilek wrote:
"Jason Hise" wrote:
Why does it require that the function which is called once not be allowed to throw? I am not sure that I can meet this requirement, as I may need to dynamically allocate memory.
Possibly because of internal implementation.
I think it's a pthreads requirement. Jonathan

Jonathan Turkanis wrote:
Pavel Vozenilek wrote:
"Jason Hise" wrote:
Why does it require that the function which is called once not be allowed to throw? I am not sure that I can meet this requirement, as I may need to dynamically allocate memory.
Possibly because of internal implementation.
I think it's a pthreads requirement.
Pthreads knows nothing about exceptions, so it can't strictly require that one isn't thrown :-) I assume it's because an exception that causes an early exit from pthread_once could prevent the "once flag" being set, which would allow the function to be run more than once. This is actually opposite to the POSIX spec for pthread_once, which explicitly says that if the thread is cancelled while running the function then it is as though pthread_once had never been called i.e. the function *can* run more than once. Thread cancellation is supposed to behave like an exception, so the Boost requirement is arguably too strict. It's probably just to be safe, since interaction between exceptions and thread cancellation is a very open issue and is far from portable. jon

Jonathan Wakely <cow@compsoc.man.ac.uk> writes:
Jonathan Turkanis wrote:
Pavel Vozenilek wrote:
"Jason Hise" wrote:
Why does it require that the function which is called once not be allowed to throw? I am not sure that I can meet this requirement, as I may need to dynamically allocate memory.
Possibly because of internal implementation.
I think it's a pthreads requirement.
Pthreads knows nothing about exceptions, so it can't strictly require that one isn't thrown :-)
It's also a 'C' library so *in general* it can't propagate an exception properly either. I'm pretty sure that's the reason for the requirement. In principle, it might crash. Of course, some systems have integrated C++ exceptions with their 'C' runtime and libraries. In fact, pthreads is more likely than most libraries to have registered the appropriate 'C' cleanups, because pthreads has a whole integrated cancellation mechanism that is intended to map to C++ exceptions. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
Jonathan Wakely <cow@compsoc.man.ac.uk> writes:
Jonathan Turkanis wrote:
I think it's a pthreads requirement.
Pthreads knows nothing about exceptions, so it can't strictly require that one isn't thrown :-)
It's also a 'C' library so *in general* it can't propagate an exception properly either. I'm pretty sure that's the reason for the requirement. In principle, it might crash. Of course, some systems
Good point.
have integrated C++ exceptions with their 'C' runtime and libraries.
Yes, David Butenhof's mails on that subject have made me very jealous :)
In fact, pthreads is more likely than most libraries to have registered the appropriate 'C' cleanups, because pthreads has a whole integrated cancellation mechanism that is intended to map to C++ exceptions.
True. Thanks for the info. jon -- "Most men pursue pleasure with such breathless anticipation that they hurry past it." - Kierkegaard

Jonathan Wakely wrote:
Jonathan Turkanis wrote:
Pavel Vozenilek wrote:
"Jason Hise" wrote:
Why does it require that the function which is called once not be allowed to throw? I am not sure that I can meet this requirement, as I may need to dynamically allocate memory.
Possibly because of internal implementation.
I think it's a pthreads requirement.
Pthreads knows nothing about exceptions,
That's not true. http://www.opengroup.org/onlinepubs/009695399/functions/pthread_once.html "The pthread_once() function is not a cancellation point. However, if init_routine is a cancellation point and is canceled, the effect on once_control shall be as if pthread_once() was never called." http://www.opengroup.org/onlinepubs/009695399/functions/pthread_cleanup_push... "Note that the specified cleanup handling mechanism is especially tied to the C language and, while the requirement for a uniform mechanism for expressing cleanup is language-independent, the mechanism used in other languages may be quite different. In addition, this mechanism is really only necessary due to the lack of a real exception mechanism in the C language, which would be the ideal solution." http://www.opengroup.org/onlinepubs/009695399/xrat/xsh_chap02.html#tag_03_02... "...it is an explicit goal of IEEE Std 1003.1-2001 to be compatible with existing exception facilities and languages having exceptions." regards, alexander. P.S. http://groups.google.de/group/comp.std.c++/msg/20a156f0b068c9e1

Alexander Terekhov wrote:
Jonathan Wakely wrote:
Pthreads knows nothing about exceptions,
That's not true.
http://www.opengroup.org/onlinepubs/009695399/functions/pthread_once.html
"The pthread_once() function is not a cancellation point. However, if init_routine is a cancellation point and is canceled, the effect on once_control shall be as if pthread_once() was never called."
Yep, that's what I referred to in my mail.
http://www.opengroup.org/onlinepubs/009695399/functions/pthread_cleanup_push...
"Note that the specified cleanup handling mechanism is especially tied to the C language and, while the requirement for a uniform mechanism for expressing cleanup is language-independent, the mechanism used in other languages may be quite different. In addition, this mechanism is really only necessary due to the lack of a real exception mechanism in the C language, which would be the ideal solution."
Good point, but as you know, it's not settled whether cancellation is a C++ exception ... but let's not start this on the Boost list as well, I have other mailboxes for that subject! :) jon -- "Accept the contradictions" - The KLF

Jonathan Wakely wrote:
Alexander Terekhov wrote:
Jonathan Wakely wrote:
Pthreads knows nothing about exceptions,
That's not true.
http://www.opengroup.org/onlinepubs/009695399/functions/pthread_once.html
"The pthread_once() function is not a cancellation point. However, if init_routine is a cancellation point and is canceled, the effect on once_control shall be as if pthread_once() was never called."
Yep, that's what I referred to in my mail.
http://www.opengroup.org/onlinepubs/009695399/functions/pthread_cleanup_push...
"Note that the specified cleanup handling mechanism is especially tied to the C language and, while the requirement for a uniform mechanism for expressing cleanup is language-independent, the mechanism used in other languages may be quite different. In addition, this mechanism is really only necessary due to the lack of a real exception mechanism in the C language, which would be the ideal solution."
Good point, but as you know, it's not settled whether cancellation is a C++ exception ... but let's not start this on the Boost list as well, I have other mailboxes for that subject! :)
It doesn't matter; the pthreads behavior just makes sense. The postcondition of pthread_once and call_once is that the function has been executed to completion exactly once (and hence, that the postconditions of the function hold). If the function has thrown an exception, it hasn't satisfied its postconditions, so call_once should not attempt to set the once_flag. That's how local statics work, too.
participants (7)
-
Alexander Terekhov
-
David Abrahams
-
Jason Hise
-
Jonathan Turkanis
-
Jonathan Wakely
-
Pavel Vozenilek
-
Peter Dimov