Subj : Re: Can C++ local static objects be made thread safe? To : comp.programming.threads From : Giancarlo Niccolai Date : Thu Feb 03 2005 09:51 pm Gianni Mariani wrote: > > Please describe how. Without imposing draconian restrictions (and > almost impossible to enforce) on the use of static locals, how do you > provide a mechanism to use them safely in a multi-threaded environment ? First of all, you can even don't use them. The only case in which you are forced to use them is if someone other's code contains them and you cannot modify it. > >> >> One (and the simplest) is to mathematically demonstrate that all the COFU >> are called before any thread is started. > > In general, that is impossible. In general, it's also impossible if you > load DLL's/DSO's dynamically (after main() is called). It's easy indeed, in 2 easy steps: 1) Don't start threads from constructors. It's a silly thing to do EVEN if you set the COFU problem aside. 2) Call all the COFU you have in the beginning of the main program; if they are already initialized, you will just loose some clock cycle at program startup, if they are not yet initialized they will be initialized safely in a spot where you can mathematically demonstrate that there are no thread running (you have not started them yet). > > This may be ensured by calling all >> the COFU from main() before starting the first thread, provider that >> constructors that may require COFU before main() do not start threads >> (which, IMHO, is a pointless, dangerous and useless thing to do even >> without the COFU problem). > > Say goodbye to plugins ? plugin->setup(); called from one thread is not enough for you? There is ONE point, and exactly one, in which the DLL is loaded into your MT app. Set it up in that point. Before that point, the DLL does not exists, in that point, ONLY ONE THREAD may know that the dll is being around, and AFTER that point, when many threads may use the plugin, the things are already setup. > >> >> Another is to use the COFU semantic to construct on first use MT aware >> objects BEFORE starting any thread, i.e. to construct a global mutex >> before there is the possibility to start any thread even from pre-main() >> code, and then use those safely constructed objects to regulate pre-main >> MT. Even if I would disagree with the need to have pre-main MT, this >> would exclude the need to call all the COFU from main() before the first >> thread is started (or to be otherwise sure that all the COFU are called). > > In general, it is somtimes impossible to know what parameters to pass to > static local constructors until after your threads are started. Then, it is your threading technique or the static initializers requirements (or both) that need to be redesigned; it has nothing to do with thread safety, also because a simple compiler driven synchronization WON'T PREVENT YOUR PROGRAM from having the same problems it had before. If a static initializer needs some data to be prepare by some SEPARATE thread in advance, then a mutex put in by the compiler won't help you. And if you really just need that... then PUT A MUTEX IN A COFU!!!! If you can demonstrate that the mutex is created before any thread is started (i.e. call the mutex creator COFU in every constructor which is going to start a thread BEFORE starting the thread), you can EVEN point directly to the created object, without having to call always the COFU routine, with 0 overhead with respect to having the mutex generated for you in the compiler. > >> >> Notice that having a COFU called from the static constructors and then >> also from main() does nothing, just ensures that the object GET >> constructed, if not during the static initializers, at least before a >> thread requires it. >> >> Notice also that the COFU semantic is needed JUST AND ONLY to avoid the >> "static initialization order fiasco"; that is, COFUing is a "trick" to >> avoid your program to break during startup if it ever needs objects to be >> constructed that way. C++ experts advise against this technique, and >> suggest to use the COFU ONLY if there isn't any other way to have your >> program run. If you can, create the objects from main or thereafter, and >> avoid using objects declared as global variable. If you can't (and you >> should motivate this inability with some strong point), then use COFU to >> prevent your program from crashing. Cfr. the C++ FAQ lite on this point. > > I'd like to know the C++ experts you're talking about. nntp://comp.lang.c++ http://www.parashift.com/c++-faq-lite/ And especially http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.11 and the followings. (and yes, that ppl IS expert, if not at the level of Dr. Stroustrup, at very near level. I.e. see a pertinent reply from one of the ppl that has contributed to the design of STL: http://groups.google.com/groups?q=static+initializer+order&hl=it&lr=&ie=UTF-8&selm=3274D95D.41C6%40aw.sgi.com&rnum=1 ). > >> >> >> Conclusion: Terekhov is right, as almost always. Having compilers >> preventing you to do silly things is silly, especially if this "rescue" >> towards the unaware programmers has a performance cost on correctly built >> programs. > > This is where I think we disagree. The whole purpose of a compiler is > to save me from having to create code that I would otherwise have to > write by hand. The question is where does that line fall. Since man > hours cost significanly more that CPU hours, the more work I can get the > compiler to do, the less cost my product will be and likely better, less > buggy as well. This is an opinion, like mine is. The problem is that in case my opinion prevails, YOU can program your way to safe MT static initialization, i.e. via COFU creation of posix mutexes, and you'll pay no more cost than having to learn how to do it, while if your opinion prevails, I'll have my initialization code mutexed out uselessly and I won't be able to prevent it. That's what "you pay for what you use" is meant, and that's way, if such a mutex in init must be, be it at least a #pragma activeable request. Ah, BTW: EVERY compiler allows you to specify the exact order of static initializers with PRAGMA directive; so, you don't really have the problem you think you have, because, if your program badly depends on things done before others during static initialization, you can just tell the compiler "ok, do this before than that plz."... Since if you need that it means that you have bad code, a #pragma or two won't make it worse. Bests, Giancarlo Niccolai. .