Subj : Re: std::msync To : comp.programming.threads From : Alexander Terekhov Date : Wed Mar 30 2005 07:24 pm < Forward Inline http://gcc.gnu.org/ml/libstdc++/2005-03/msg00371.html> -------- Original Message -------- Message-ID: Subject: Re: [patch] Make std::tr1::shared_ptr thread-safe. "Peter Dimov" on 03/30/2005 04:36:54 PM: > > Alexander Terekhov wrote: > > [... __release/acquire_memory_barrier() ...] > > > >> The only reliable implementation of these barriers that I see > >> is an empty pthread_mutex_lock/pthread_mutex_unlock pair. > > > > Nope. That won't work. [...] > > Update: > > I think that we've reached the conclusion that the following > implementation: > > void release() // nothrow > { > if (__gnu_cxx::__exchange_and_add(&_M_use_count, -1) == 1) > { > pthread_mutex_lock( &_M_mutex ); > dispose(); > pthread_mutex_unlock( &_M_mutex ); > weak_release(); > } > } void release() // nothrow { if (__gnu_cxx::__exchange_and_add(&_M_use_count, -1) == 1) { dispose(); pthread_mutex_lock( &_M_mutex ); pthread_mutex_unlock( &_M_mutex ); weak_release(); } } would also work. The key here is... > > void weak_release() // nothrow > { > if (__gnu_cxx::__exchange_and_add(&_M_weak_count, -1) == 1) > { > pthread_mutex_lock( &_M_mutex ); > pthread_mutex_unlock( &_M_mutex ); > destroy(); > } > } to have the same lock on both sides. Some "thread-specific" locks to "emulate" bidirectional fences with minimum contention won't work. > > will work *provided that __exchange_and_add imposes at least the ordering > that is required for reference-counted immutable objects to work*. That's msync::slb (relaxed msync::rel not affecting sinking of preceding stores) when result > 1 and msync::cchsb (relaxed msync::acq [cc stands control condition hint] not affecting hoisting of subsequent loads) when result == 0. No _M_mutex above is needed with more constrained version of __exchange_and_add() providing msync::rel when result > 1 and msync::ccacq when result == 0. Such semantics will also support basic thread-safety of shared_ptr<> for mutable managed objects without unpleasant requirement for client provided synchronizing deleters. > > The last point is important, because it affects the other uses of > __exchange_and_add in libstdc++. > > Alexander has identified the following problematic case: > > // thread A > > read *p1 > p1.drop_reference() > > // thread B > > p2.drop_reference(); // destroys *p1 > > If the __exchange_and_adds hidden in drop_reference do not establish > ordering, it is possible for *p1 to be destroyed (and the storage > invalidated, zeroed or reused) by thread B before the read in thread A. Yep. regards, alexander. .