Subj : Re: Can C++ local static objects be made thread safe? To : comp.programming.threads From : Marcin 'Qrczak' Kowalczyk Date : Thu Feb 10 2005 11:23 am gniccolai@yahoo.com (Giancarlo Niccolai) writes: >> As with pthread_once, with PTHREAD_ONCE_INIT. > > Ok for pthread_once to initialize the mutex; but if initializing > unneeded mutexes is not a problem for you, I can assure that is a > problem for me (and for many others). Usually it's not unneeded. Leaving static local unprotected in a MT program is usually wrong. You should either move it outside the function, so it's initialized at the beginning of the program, or protect it against concurrent initialization. With the proposed change the second case just works, without additional code. > I hope that this explain why mutex applied to "code section" are > basically wrong: mutex are meant to guard data access on a data set. It guards the object during its initialization. > A data set guarded by a mutex needs NOT to coincide with a whole class. > I may i.e. legally create a data set merging PART of a class data and > another data set with other PARTS of the same class data. This code > won't be made safe by locking its initializers. Ok, in rare cases where your classes are so poorly mapped to the problem domain that it doesn't work (is there a practical such case?) you must add some other synchronization. But synchronizing initialization of static locals never hurts: Either the initializer would not be entered concurrently anyway and the synchronization is a noop; or it would be entered by the same thread and both versions are broken (mine: deadlock or error depending on how pthread_once is implemented, yours: undefined behavior resulting from entering an initializer recursively); or it would be entered by a different thread and then my version works (in the absence of other errors) and your version will definitely not work (same undefined behavior as previously). > LOCKING is to lock data, NOT PROCESSING. By forcing mutexes to guard > the process, and not the data sets (because the compiler has no idea > about the data sets I am using), you are misusing mutexes. And > misusing things brings bad luck... Fortunately compilers don't care about luck, they only care about correctness, and a program with guarded static locals is never less correct than a program without. Either both will work, or only the synchronized one will work, or none will work. > 1) Demonstrate that the thing is an EXISTING problem. That is, > demonstrate that the average threaded program does static > initialization wrong (because the average programmer needs the help > of the compiler). I have shown the read_unicode_database_from_file example. A piece of code written with no MT in mind will work in MT with my semantics and will not work with your semantics. I don't have a more real-life examples because I avoid C++ as a plague. > 2) demonstrate that using a mutex across any possible data set (and > any possible function call) does not break any possible program. It's not an arbitrary data set, it's intialization of a given variable. As I said above ("Either the initializer...") it's either harmless, or the original was broken anyway, or it actually makes it correct. > 3) (well, this is a matter of taste, but however you may try to > demonstrate that complex applications are simpler/more > robust/safer/nicer if using static initializers to build singletons). You don't have to use static locals, feel free to implement your own locking around explicitly called initialization of a global variable, but please don't make static locals MT-unsafe by default. -- __("< Marcin Kowalczyk \__/ qrczak@knm.org.pl ^^ http://qrnik.knm.org.pl/~qrczak/ .