Subj : Re: Can C++ local static objects be made thread safe? To : comp.programming.threads From : David Schwartz Date : Fri Jan 21 2005 12:12 pm "Gianni Mariani" wrote in message news:iaudnW0LQIcam2zcRVn-ig@speakeasy.net... > It seems as though > > ac_cpu_mb_consumer_depends() > and > ac_cpu_mb_producer(); > > are only applicable for non cache-coherent systems. No, they're applicable on any machine that can reorder writes without automatically invalidating speculative fetches. > Which architectures need memory barriers ? x86 does in theory. No present x86 processor does, but this is due to behavior Intel has speficially cautioned is subject to change. > CCNUMA machines are in theory, cahce cohereant, so do they require memory > barriers ? Yes, of course. The problem is things like this: Foo *j=NULL; // ... j=new Foo(x); Another thread might 'see' j contain the value returned by 'new' without seeing all the other writes done in the constructor. Imagine if the constructor is just: Foo::Foo(void) { m_int=3; } Without a memory barrier, another thread might see j as non-NULL without seeing the write to m_int. Thus accessing 'j' might lead to undefined results. All this takes is posted writes and speculative reads. > Do all of these architectures have barrier instuctions with the same > semantics ? No. That's why the examples use excessive detail. Some architectures have only a single synch instruction. Some have many fine-grained ones. > Is this below going to perform as advertised ? > ThreadLocal, MemoryBarrierSyncReads and MemoryBarrierSyncWrites > are mythical things at this time. > > The idea is that once each thread has successfully traversed the > initialization, it really doesn't need to bother synchronizing second time > around. > > #define MTSafeStatic( Type, Name, Initializer ) \ > static Type * x_ ## Name; \ > Type * xlocal_ ## Name = x_ ## Name; \ > \ > ThreadLocal m_val; \ > \ > if ( ! m_val ) \ > { \ > MemoryBarrierSyncReads(); \ > } \ > \ > if ( ! xlocal_ ## Name ) \ > { \ > Lock l_lock( StaticInitializerMutex ); \ > \ > if ( ! x_ ## Name ) \ > { \ > static Type v_ ## Name Initializer; \ > \ > MemoryBarrierSyncWrites(); \ > x_ ## Name = & v_ ## Name ; \ > xlocal_ ## Name = & v_ ## Name; \ > } \ > } \ > \ > m_val = true; \ > \ > Type & Name = * xlocal_ ## Name; \ > // End macro This isn't quite right. Another thread could see 'm_val' as true, and the 'xlocal' as non-NULL and still not see the writes inside 'x'. You need a memory barrier in every possible case, unfortunately. Not all architectures provide a way for one thread to force another thread to see something. DS .