Poco RefCountedObject offer 2 interfaces:
inline void RefCountedObject::duplicate() const
{
++_counter;
}
inline void RefCountedObject::release() const throw()
{
try
{
if (--_counter == 0) delete this;
}
catch (...)
{
poco_unexpected();
}
}
With:
class Foundation_API RefCountedObject
/// A base class for objects that employ
/// reference counting based garbage collection.
///
/// Reference-counted objects inhibit construction
/// by copying and assignment.
{
public:
RefCountedObject();
/// Creates the RefCountedObject.
/// The initial reference count is one.
void duplicate() const;
/// Increments the object's reference count.
void release() const throw();
/// Decrements the object's reference count
/// and deletes the object if the count
/// reaches zero.
int referenceCount() const;
/// Returns the reference count.
protected:
virtual ~RefCountedObject();
/// Destroys the RefCountedObject.
private:
RefCountedObject(const RefCountedObject&);
RefCountedObject& operator = (const RefCountedObject&);
mutable AtomicCounter _counter;
};
Note that: mutable AtomicCounter _counter;
my question is if I use a RefCountedObject in multithreading is it safe?
In my opinion it's not because only --_counter is atomic but if(--_count) is not atomic and could lead to having a reference to a deleted object. For example let say I have 2 threads A and B one executing duplicate and the other release, the execution sequence is as follow:
We end up with A having a reference to a deleted object. even if the mutable keyword force the compiler to not optimize the _counter it won't help in multithreading
Am I missing something?
Strictly from looking at duplicate and release in isolation, the above is correct.
However, if you have two threads, both having a pointer to the same RefCountedObject, you either should have separate AutoPtr instances in each thread (which implies the _counter is > 1 to begin with), or, if you share the same AutoPtr, it must be protected by a mutex, if at least one thread can change the AutoPtr (which would result in release() being called). Needless to say sharing an mutable AutoPtr between multiple threads is a recipe for disaster.
If you manage RefCountedObject by manually calling duplicate() and release() (which I would not recommend), you should follow POCO's reference counting rules and be very careful.
So, for well-behaved code, RefCountedObject together with AutoPtr is safe for multithreaded use.