There is a scenario that i need to solve with shared_ptr and weak_ptr smart pointers.
Two threads, thread 1 & 2, are using a shared object called A. Each of the threads have a reference to that object. thread 1 decides to delete object A but at the same time thread 2 might be using it. If i used shared_ptr to hold object A's references in each thread, the object wont get deleted at the right time.
What should i do to be able to delete the object when its supposed to and prevent an error in other threads that using that object at the same time?
There's 2 cases:
One thread owns the shared data
If thread1 is the "owner" of the object and thread2 needs to just use it, store a weak_ptr in thread2. Weak pointers do not participate in reference counting, instead they provide a way to access a shared_ptr to the object if the object still exists. If the object doesn't exist, weak_ptr will return an empty/null shared_ptr.
Here's an example:
class CThread2
{
private:
boost::weak_ptr<T> weakPtr
public:
void SetPointer(boost::shared_ptr<T> ptrToAssign)
{
weakPtr = ptrToAssign;
}
void UsePointer()
{
boost::shared_ptr<T> basePtr;
basePtr = weakPtr.lock()
if (basePtr)
{
// pointer was not deleted by thread a and still exists,
// so it can be used.
}
else
{
// thread1 must have deleted the pointer
}
}
};
My answer to this question (link) might also be useful.
The data is truly owned by both
If either of your threads can perform deletion, than you can not have what I describe above. Since both threads need to know the state of the pointer in addition to the underlying object, this may be a case where a "pointer to a pointer" is useful.
boost::shared_ptr< boost::shared_ptr<T> >
or (via a raw ptr)
shared_ptr<T>* sharedObject;
or just
T** sharedObject;
Why is this useful?
- You only have one referrer to T (in fact shared_ptr is pretty redundant)
- Both threads can check the status of the single shared pointer (is it NULL? Was it deleted by the other thread?)
Pitfalls:
- Think about what happens when both sides try to delete at the same time, you may need to lock this pointer
Revised Example:
class CAThread
{
private:
boost::shared_ptr<T>* sharedMemory;
public:
void SetPointer(boost::shared_ptr<T>* ptrToAssign)
{
assert(sharedMemory != NULL);
sharedMemory = ptrToAssign;
}
void UsePointer()
{
// lock as needed
if (sharedMemory->get() != NULL)
{
// pointer was not deleted by thread a and still exists,
// so it can be used.
}
else
{
// other thread must have deleted the pointer
}
}
void AssignToPointer()
{
// lock as needed
sharedMemory->reset(new T);
}
void DeletePointer()
{
// lock as needed
sharedMemory->reset();
}
};
I'm ignoring all the concurrency issues with the underlying data, but that's not really what you're asking about.
Qt has a QPointer class that does this. The pointers are automatically set to 0 if what they're pointed at is deleted.
(Of course, this would only work if you're interested in integrating Qt into your project.)