views:

859

answers:

2

In the absence of multithreading, the implementation of copy-on-write for shared_ptr (either from boost or tr1) using unique() is straightforward. Which changes need to be made when multithreading? The reference count is atomic so I assume I can create, copy-construct, read and destroy instances of shared_ptr without further concerns. How about updating them, in general, and particularly when implementing copy-on-write? Are locks needed? Or use boost::atomic_store (why is it not documented)? Or wait for a fully atomic version of shared_ptr (not an option)?

Edit:
sfossen, thank you for your helpful reply.
So I conclude that if I change a pointed-to object only after detaching it via COW, so that only the current thread owns it, no locking is needed and the COW implementation looks just like the single-threaded one when using shared_ptr with atomic ref-counts.

+4  A: 

With COW you only need locking when copying objects that may be in the middle of being changed.

So if the COW of the object, is an object set up before the threads and never changes, no locking required.

However if you are making copies of the copies, then you need to atleast lock during the initial write, or make sure that the copy has all changes before being able to be copied again.

If you can't completely guarantee those, then use locking or atomic updates.

If you want locking:

There does appear to be an atomic version in the trunk right now.

If you can't update boost, you could either import the required functions for now or wrap it in a lock like the reader/writer lock.

from shared_ptr.hpp

template<class T> shared_ptr<T> atomic_exchange( shared_ptr<T> * p, shared_ptr<T> r )
{
    boost::detail::spinlock & sp = boost::detail::spinlock_pool<2>::spinlock_for( p );

    sp.lock();
    p->swap( r );
    sp.unlock();

    return r; // return std::move( r )
}

article on RWLocks

sfossen
A: 

It is not safe to copy a shared_ptr without some form of synchronization unless it is otherwise owned by the thread doing the copying. The thread safety guarantees only apply to shared_ptr's that are owned by a thread where the shared_ptr's internal reference count may be shared by shared_ptr's owned by other threads.

The behavior you want is that I'd call atomically thread-safe which doesn't currently exist in shared_ptr and probably won't even after C++0x. The name shared_ptr is probably a little confusing here since you can't really share a shared_ptr between threads without synchronization.