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.)
Related
I have a situation where I have a piece of hardware and it really only makes sense for a single connection to be open on that hardware at the same time, so I really only want to refer to one object no matter where it's passed. So it may look something like:
class Hardware {
public:
void Open(); //this will create and launch a connection monitor in the background
void Close();
std::string SendPing();
std::string AskForSomeOtherData();
bool isConnected();
bool setConnected(bool connState);
private:
bool connected_;
int hndl_;
}
I then have another class monitoring the connection in the background so my UI can be notified if a connection is lost.
class ConnectionMonitor{
ConnectionMonitor(Hardware& hw);
void Run(); //launches a background thread to send "pings" to the device to make sure it's there. Will update Hardware.connected_
Hardware hw_; //or Hardware* hw_, or shared_ptr<Hardware> hw_, or Hardware& hw_;
}
When the connection monitor notices a connection is lost, it needs to update the connected boolean of the hardware object passed in directly, because my other threads using the object will also want to know it's been disconnected. But I don't know if updating the private data of the object indicates ownership of the object itself?
I don't believe so, since the lifetime of the object shouldn't be effected. There are all these different ways to pass an object shared between two classes, but I don't know what the problem domain calls for when I need to store it in class private data. Requiring a shared pointer to be passed in is one option. But I am not really indicating any ownership of the object being taken I don't think? A reference seems to be more fitting possibly, but then I end up with needing Hardware& hw; in my ConnectionMonitor private data so I keep a reference to the Hardware object. Then I read stuff that says "Reference in private data bad."
Also, if the caller is storing the hardware object as a shared_ptr, I believe I would have to do something like the following to pass it into my ConnectionMonitor:
ConnectionMonitor(*hardware);
but is this ok for a shared pointer, to dereference it, pass the object to a constructor, and then have the consuming class store another pointer to the same object that the shared pointer owns?
ConnectionMonitor(Hardware& hw){
Hardware* = hw; //not 100% sure if this syntax is correct, still learning. Most importantly here I'd be taking the hw object being referenced and pointing at it internally, rather than creating a copy
}
It seems now I am now creating a pointer to an object that the shared pointer already owns.
There are a lot of questions embedded above in what amounts to be a brain dump on my thought process, so I will try to summarize. When two threads need access to the same resource, and that resource needs to be updated from either thread, is this a case for a shared pointer? If one of the classes is not taking ownership, what is the best way to store that shared object in private data?
but is this ok for a shared pointer, to dereference it, pass the object to a constructor, and then have the consuming class store another pointer to the same object that the shared pointer owns?
Yes raw pointers are fine when the are non-owning. You can use std::shared_ptr::get to retrieve the stored raw pointer. However, when you store the raw pointer you need to consider the lifetime of the object. For example this is fine:
#include <memory>
#include <iostream>
struct bar {
std::shared_ptr<int> owning_ptr;
bar() : owning_ptr(std::make_shared<int>(42)) {}
~bar() { std::cout << "bar destructor\n"; }
};
struct foo {
int* non_owning_ptr;
~foo() { std::cout << "foo destructor\n"; }
};
struct foobar {
bar b;
foo f;
foobar() : b(),f{b.owning_ptr.get()} {}
};
int main() {
foobar fb;
}
b gets initialized first and f can use a pointer to the int managed by owning_ptr. Because f gets destroyed first, there is no danger of f using non_owning_ptr after owning_ptr already deleted the int.
However, only in certain circumstances you can be certain that the raw pointer can only be used as long as the object managed by a smart pointer is alive. As mentioned in a comment, the non-owning counter part to std::shared_ptr is std::weak_ptr. It does not increment the reference count, hence does not prevent the managed object to be deleted when all std::shared_ptrs to the object are gone.
#include <memory>
#include <iostream>
struct moo {
std::weak_ptr<int> weak;
void do_something() {
std::shared_ptr<int> ptr = weak.lock();
if (ptr) { std::cout << "the int is still alive: " << *ptr << "\n"; }
else { std::cout << "the int is already gone\n"; }
}
};
int main() {
moo m;
{
std::shared_ptr<int> soon_gone = std::make_shared<int>(42);
m.weak = soon_gone;
m.do_something();
}
m.do_something();
}
Output is:
the int is still alive: 42
the int is already gone
As already mentioned the std::weak_ptr does not keep the object alive. Though, it has a lock method that locks the object from being destroyed as long as the returned std::shared_ptr is alive. When lock is called on the weak_ptr when the object is already gone, also the returned shared pointer is empty.
When two threads need access to the same resource, and that resource needs to be updated from either thread, is this a case for a shared pointer?
Yes and no. The ref counting of std::shared_ptr is thread safe. Though using a shared pointer does not automagically make the pointee thread safe. You need some synchronization mechanism to avoid data races.
This question already has answers here:
About thread-safety of weak_ptr
(5 answers)
Closed 4 years ago.
Below is some sample code showing my use case. I have a PIMPL where the implementation can be shared (it's just a bunch of expensively-produced data) but the implementation can be destroyed when it's no longer needed. An instance of the class HasImpl uses a shared pointer to Impl, and the class definition includes a static weak_ptr to Impl that acts as a "pointer dispenser" to new instances of HasImpl, giving them a handle to the Impl if one exists already.
The sample has two alternatives for calling weak_ptr::lock--one that assumes that the the answer to questions 1-3 below are all "yes", and another that does not. The only reason I'd prefer that weak_ptr::lock is thread-safe is that there could be multiple threads trying to get a copy of the pointer to Impl, and if lock is thread-safe, most threads of execution won't have to pass a static variable definition (where the thread would have to check to see if it were already initialized) and won't have to compete to acquire a mutex.
/* In HasImpl.h */
class HasImpl {
public:
HasImpl();
private:
class Impl;
static std::weak_ptr<Impl> sharedImplDispenser;
std::shared_ptr<Impl> myPtrToSharedImpl;
}
/* In HasImpl.cpp */
class HasImpl::Impl {
public:
Impl(); //constructor that takes a lot of time to run
//Lots of stuff, expensively produced, accessable to HasImpl through a shared_ptr to Impl
}
/* hypothetical constructor if weak_ptr::lock is thread-safe */
HasImpl::HasImpl() : myPtrToSharedImpl{sharedImplDispenser.lock()}
{
if (!myPtrToSharedImpl) {
static std::mutex mtx;
std::lockguard<std::mutex> lck(mtx);
myPtrToSharedImpl = sharedImplDispenser.lock();
if (!myPtrToSharedImpl) {
const auto new_impl{std::make_shared<Impl()};
sharedImplDispenser = new_impl; // the only place in the program where a value is assigned to sharedImplDispenser
myPtrToSharedImpl = new_impl;
}
}
}
/* hypothetical constructor if weak_ptr::lock is not thread-safe */
HasImpl::HasImpl()
{
static std::mutex mtx;
std::lockguard<std::mutex> lck(mtx);
myPtrToSharedImpl = sharedImpl.lock();
if (!myPtrToSharedImpl) {
const auto new_impl{std::make_shared<Impl()};
sharedImplDispenser = new_impl; // the only place in the program where a value is assigned to sharedImplDispenser
myPtrToSharedImpl = new_impl;
}
}
Assuming that std::weak_ptr is not empty and was assigned a pointer sometime in the distant past, will the control block be ok if one thread calls weak_ptr::lock while another thread may be calling weak_ptr::lock?
Is calling weak_ptr::lock while another thread may be assigning a ptr to an empty weak_ptr safe enough? That is, will the value either return nullptr or the new pointer? I don't care if the nullptr is spurious (that is, that assignment has occurred but the other threads don't know about it yet). I just don't want to corrupt the control block or obtain an invalid pointer value from the call.
Is calling weak_ptr::lock while the last shared_ptr to the object is being destroyed thread safe?
If there are problems with 1 through 3, will std::atomic<std::weak_ptr<T>> in C++20 fix the issue?
The standard explicitly says that weak_ptr::lock is "executed atomically". So that answers 1 and 3.
For #2, if you're asking about assigning to the same weak_ptr, then it's a data race. Operations that change a shared state's use_count don't provoke a data race, but copying or manipulating the weak_ptr itself is doing more than just poking at use_count.
But if you're talking about locking one weak_ptr while nulling out a different weak_ptr that are both talking to the same shared state, that's fine. The two only interact through the shared state's count, which is stated to be fine.
And yes, atomic<weak_ptr<T>> would allow you to manipulate the same object from multiple threads.
The code I'm currently working on had it's own RefPtr implementation which was failing at random.
I suspect that this could be a classic data race. RefPtr has a pointer to original object that inherits from the RefCounted class. This class contains a reference counter (m_refCount) that is not atomic and an application was crashing inside some threadwork accessing object through RefPtr stuff. Just like the object under RefPtr got destroyed. Quite impossible.
The object instance that is held by RefPtr is also held by two other objects that do not modify it (or its contents) and I'm 100% sure that they have shared ownership of it (so m_refCount should never go below 2)
I did try to replace the pointer with std::shared_ptr, but the crash is still there.
The distilled code representing this issue:
class SharedObjectA
{
public:
int a;
}
class Owner
{
public:
shared_ptr<SharedObjectA> objectA;
}
class SecondOwner
{
shared_ptr<SharedObjectA> objcectA;
public:
shared_ptr<SharedObjectA> GetSharedObject() { return objectA;}
void SetSharedObject(shared_ptr<SharedObjectA> objA) { objectA = objA;}
}
void doSomethingThatTakesTime(SecondOwnerA* owner)
{
sleep(1000+rand()%1000);
shared_ptr<SharedObjectA> anObject = owner->GetSharedObject();
int value = anObject.a;
std::cout << " says: " << value;
}
int main()
{
Owner ownerA;
ownerA.objectA.reset(new SharedObjectA());
SecondOwner secondOwner;
secondOwner.SetSharedObject(ownerA.objectA);
//objectA instance
while(true)
{
for(int i=0;i<4;i++)
{
std::thread tr(doSomethingThatTakesTime,secondOwner);
}
sleep(4*1000);
}
}
What's happening is up to 4 threads access SharedObject using GetSharedObject and do something with it.
However, after giving it some time - the use_count() of shared_ptr will go down below 2 (it should not) and eventually below 1 so the object(objectA) will get destroyed.
Edit
Obviously there is no synchronization in this code. However i don't see how this could be related to the fact the use_count() getting below 2. the shared_ptr is guaranteed to be thread safe for the sake of reference counting, isn't it?
You don't have any kind of synchronization on access to the shared object. shared_ptr does not do any synchronization in access to the pointed-to object, it just ensures that the memory pointed to gets released after all references to it are destroyed.
You also need to join() your threads at some point.
I have a threaded class from which I would like to occasionally acquire a pointer an instance variable. I would like this access to be guarded by a mutex so that the thread is blocked from accessing this resource until the client is finished with its pointer.
My initial approach to this is to return a pair of objects: one a pointer to the resource and one a shared_ptr to a lock object on the mutex. This shared_ptr holds the only reference to the lock object so the mutex should be unlocked when it goes out of scope. Something like this:
void A::getResource()
{
Lock* lock = new Lock(&mMutex);
return pair<Resource*, shared_ptr<Lock> >(
&mResource,
shared_ptr<Lock>(lock));
}
This solution is less than ideal because it requires the client to hold onto the entire pair of objects. Behaviour like this breaks the thread safety:
Resource* r = a.getResource().first;
In addition, my own implementation of this is deadlocking and I'm having difficulty determining why, so there may be other things wrong with it.
What I would like to have is a shared_ptr that contains the lock as an instance variable, binding it with the means to access the resource. This seems like something that should have an established design pattern but having done some research I'm surprised to find it quite hard to come across.
My questions are:
Is there a common implementation of this pattern?
Are there issues with putting a mutex inside a shared_ptr that I'm overlooking that prevent this pattern from being widespread?
Is there a good reason not to implement my own shared_ptr class to implement this pattern?
(NB I'm working on a codebase that uses Qt but unfortunately cannot use boost in this case. However, answers involving boost are still of general interest.)
I'm not sure if there are any standard implementations, but since I like re-implementing stuff for no reason, here's a version that should work (assuming you don't want to be able to copy such pointers):
template<class T>
class locking_ptr
{
public:
locking_ptr(T* ptr, mutex* lock)
: m_ptr(ptr)
, m_mutex(lock)
{
m_mutex->lock();
}
~locking_ptr()
{
if (m_mutex)
m_mutex->unlock();
}
locking_ptr(locking_ptr<T>&& ptr)
: m_ptr(ptr.m_ptr)
, m_mutex(ptr.m_mutex)
{
ptr.m_ptr = nullptr;
ptr.m_mutex = nullptr;
}
T* operator ->()
{
return m_ptr;
}
T const* operator ->() const
{
return m_ptr;
}
private:
// disallow copy/assignment
locking_ptr(locking_ptr<T> const& ptr)
{
}
locking_ptr& operator = (locking_ptr<T> const& ptr)
{
return *this;
}
T* m_ptr;
mutex* m_mutex; // whatever implementation you use
};
You're describing a variation of the EXECUTE AROUND POINTER pattern, described by Kevlin Henney in Executing Around Sequences.
I have a prototype implementation at exec_around.h but I can't guarantee it works correctly in all cases as it's a work in progress. It includes a function mutex_around which creates an object and wraps it in a smart pointer that locks and unlocks a mutex when accessed.
There is another approach here. Far less flexible and less generic, but also far simpler. While it still seems to fit your exact scenario.
shared_ptr (both standard and Boost) offers means to construct it while providing another shared_ptr instance which will be used for usage counter and some arbitrary pointer that will not be managed at all. On cppreference.com it is the 8th form (the aliasing constructor).
Now, normally, this form is used for conversions - like providing a shared_ptr to base class object from derived class object. They share ownership and usage counter but (in general) have two different pointer values of different types. This form is also used to provide a shared_ptr to a member value based on shared_ptr to object that it is a member of.
Here we can "abuse" the form to provide lock guard. Do it like this:
auto A::getResource()
{
auto counter = std::make_shared<Lock>(&mMutex);
std::shared_ptr<Resource> result{ counter, &mResource };
return result;
}
The returned shared_ptr points to mResource and keeps mMutex locked for as long as it is used by anyone.
The problem with this solution is that it is now your responsibility to ensure that the mResource remains valid (in particular - it doesn't get destroyed) for that long as well. If locking mMutex is enough for that, then you are fine.
Otherwise, above solution must be adjusted to your particular needs. For example, you might want to have the counter a simple struct that keeps both the Lock and another shared_ptr to the A object owning the mResource.
To add to Adam Badura's answer, for a more general case using std::mutex and std::lock_guard, this worked for me:
auto A::getResource()
{
auto counter = std::make_shared<std::lock_guard<std::mutex>>(mMutex);
std::shared_ptr<Resource> ptr{ counter, &mResource} ;
return ptr;
}
where the lifetimes of std::mutex mMutex and Resource mResource are managed by some class A.
I believe I've got a good handle on at least the basics of multi-threading in C++, but I've never been able to get a clear answer on locking a mutex around shared resources in the constructor or the destructor. I was under the impression that you should lock in both places, but recently coworkers have disagreed. Pretend the following class is accessed by multiple threads:
class TestClass
{
public:
TestClass(const float input) :
mMutex(),
mValueOne(1),
mValueTwo("Text")
{
//**Does the mutex need to be locked here?
mValueTwo.Set(input);
mValueOne = mValueTwo.Get();
}
~TestClass()
{
//Lock Here?
}
int GetValueOne() const
{
Lock(mMutex);
return mValueOne;
}
void SetValueOne(const int value)
{
Lock(mMutex);
mValueOne = value;
}
CustomType GetValueTwo() const
{
Lock(mMutex);
return mValueOne;
}
void SetValueTwo(const CustomType type)
{
Lock(mMutex);
mValueTwo = type;
}
private:
Mutex mMutex;
int mValueOne;
CustomType mValueTwo;
};
Of course everything should be safe through the initialization list, but what about the statements inside the constructor? In the destructor would it be beneficial to do a non-scoped lock, and never unlock (essentially just call pthread_mutex_destroy)?
Multiple threads cannot construct the same object, nor should any thread be allowed to use the object before it's fully constructed. So, in sane code, construction without locking is safe.
Destruction is a slightly harder case. But again, proper lifetime management of your object can ensure that an object is never destroyed when there's a chance that some thread(s) might still use it.
A shared pointer can help in achieving this eg. :
construct the object in a certain thread
pass shared pointers to every thread that needs access to the object (including the thread that constructed it if needed)
the object will be destroyed when all threads have released the shared pointer
But obviously, other valid approaches exist. The key is to keep proper boundaries between the three main stages of an object's lifetime : construction, usage and destruction. Never allow an overlap between any of these stages.
They don't have to be locked in the constructor, as the only way anyone external can get access to that data at that point is if you pass them around from the constructor itself (or do some undefined behaviour, like calling a virtual method).
[Edit: Removed part about destructor, since as a comment rightfully asserts, you have bigger issues if you're trying to access resources from an object which might be dead]