This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [patch] Make std::tr1::shared_ptr thread-safe.


"Peter Dimov" <pdimov@mmltd.net> 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.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]