Does C++ offer a thread-safe reference counter? - c++

Is there a thread-safe reference counter class in the standard C++ library, (or as an extension in Visual Studio), or would I need to write this kind of object from scratch?
I'm hoping for an object that purely performs reference counting as shared_ptr might, with the exception that it does so across multiple threads accurately, and without managing anything. shared_ptr and it's cousin structures are nice because they define all the copy constructors and assignment operators you'd need, which ... are the most error prone part of C++ to me; C++ Constructors are to C++ what the Kick-off is to American Football.
struct Fun {
// this member behaves in a way I appreciate, save for 2 short-comings:
// - needless allocation event (minor)
// - ref counting is only estimate if shared across threads (major)
std::shared_ptr<int> smartPtr {new int};
// this is the hypothetical object that I'm searching for
// + allocates only a control block for the ref count
// + refCount.unique() respects reality when refs exist across many threads
// I can always count on this being the last reference
std::object_of_desire refCount;
// no explicit copy constructors or assignment operators necessary
// + both members of this class provide this paperwork for me,
// so I can careless toss this Fun object around and it'll move
// as one would expect, making only shallow copies/moves and ref counting
Fun();
~Fun(){
if(refCount.unique()){
smart_assert("I swear refCount truly is unique, on pain of death");
}
}
}

The warnings about thread safety w.r.t. std::shared_ptr are
If you have multiple threads that can access the same pointer object, then you can have a data race if one of those threads modifies the pointer. If each thread has it's own instance, pointing to the same shared state, there are no data races on the shared state.
The final modification of the pointed-to object on a thread does not inter-thread happens before another thread observing a use_count of 1. If nothing is modifying the pointed-to object, there are no data races on the pointed-to object.
Here's your desired type
class ref_count {
public:
bool unique() const { return ptr.use_count() == 1; }
private:
struct empty {};
std::shared_ptr<empty> ptr = std::make_shared<empty>();
};

Related

Thread safety of std::shared_ptr<std::mutex>

Consider the following class with a shared_ptr data object. The purpose is to obtain cheaply copyable objects with a data cache shared among the copies.
#include <memory> // std::shared_ptr
#include <mutex> // std::mutex, std::lock_guard
class DataClass {
std::shared_ptr<DataType> data;
std::shared_ptr<std::mutex> data_lock;
public:
DataClass() : data(std::make_shared<DataType>()), data_lock(std::make_shared<std::mutex>()) {}
DataType get_data() const {
std::lock_guard<std::mutex> lock_guard(*data_lock);
if (/* data not cached */) {
/* calculate and store data */
}
return *data;
}
};
Are calls to get_data() thread-safe? If not, how can that be achieved?
I do have code that seems to end up in a deadlock (far too large/complicated to post), which relies on the above to work fine in parallel calculations.
Are calls to get_data() thread-safe?
As long as data_lock is not modified after the initialization in the DataClass constructor, it is thread-safe. shared_ptr itself is not thread-safe beyond reference counting, meaning that if the pointer itself is modified, it must be protected with a mutex. If it remains constant (which you can ensure by marking data_lock with const) then multiple threads can read the pointer concurrently, including copying the pointer and incrementing/decrementing the reference counter.
If not, how can that be achieved?
If you do have an instance where data_lock can be modified, you must protect it with a mutex lock or otherwise guarantee that the modification cannot happen while other threads are accessing the pointer. In this particular case this would probably mean to get rid of data_lock pointer and replace it with a mutex.
You should also take care to not allow the pointed object to be accessed after data_lock is modified. Remember that dereferencing shared_ptr returns a raw reference without incrementing the reference counter. If that shared_ptr is modified, the object it previously pointed to can be destroyed and the raw references become dangling. This can happen in a subtle way, e.g. a reference to the mutex may be saved in a lock_guard, so after you modify data_lock under the lock the lock_guard destructor will attempt to unlock an already destroyed mutex.

Is std::weak_ptr<T>::lock thread-safe? [duplicate]

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.

Locking shared resources in constructor and destructor

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]

Is there a boost::weak_intrusive_pointer?

For legacy reasons I need to use intrusive pointers, as I need the ability to convert raw pointers to smart pointers.
However I noticed there is no weak intrusive pointer for boost. I did find a talk about it on the boost thread list, however nothing concrete.
Does anyone know of a thread safe implementation of weak intrusive pointer?
Thanks
Rich
It does not make any sense.
To elaborate: weak_ptr points to the same instance of a counter object that shared_ptr do. When the shared_ptr goes out of scope, the instance of the counter stays (with a count effectively at 0), which allows the weak_ptr instances to check that they effectively point to a freed object.
With Intrusive Counting, the counter is integrated within the object. When the count reaches 0, the object is usually either recycled or deleted... but the point is the counter is no longer available. The rationale is that this allow for a more efficient storage (1 single chunk) and greater speed (cache locality).
If you need Weak Reference counting and do not care for the benefits of intrusive counting, you can use a combination of shared_ptr and weak_ptr.
The idea is to deassociate the counter from the objects.
class Counted
{
// bla
private:
boost::shared_ptr<int> mCounter;
};
Now you can return weak handles:
class WeakHandle
{
public:
explicit WeakHandle(Counted& c): mCounter(c.mCounter), mObject(&c) {}
bool expired() const { return mCounter.expired(); }
private:
boost::weak_ptr<int> mCounter;
Counted* mObject;
};
Here, we deassociate the lifetime of the counter from the lifetime of the object, so that it will survive the destruction of the object... partially. Thus making the weak_ptr effectively possible.
And of course, using shared_ptr and weak_ptr this is Thread Safe ;)
I didn't really like either of the previous answers so:
No, I don't know of an implementation, but I think it is possible. The standard implementation of the shared_ptr holds two reference counts, one for the "strong" and one for the "weak" references, and a pointer to the referent. In an intrusive_ptr implementation the strong count needs to be part of the object, but the weak can't be. So, it seems like you could create a "weakable" intrusive_ptr.
Define a weak pointer helper:
template<class X>
class intrusive_ptr_weak_helper {
long weak_ref_count;
X *target_instance;
};
Then record that into the object beside the reference count:
struct X {
...
intrusive_ptr_weak_helper *ref_weak_helper;
...
long ref_count;
...
};
When constructing X:
ref_count = 0;
ref_weak_helper = NULL;
The "strong" pointer, intrusive_strong_ptr, is identical to intrusive_ptr, until deletion occurs. When the strong ref count goes to zero (before deletion occurs):
if (ref_weak_helper != NULL) {
if (ref_weak_helper->weak_ref_count == 0)
delete ref_weak_helper;
else
ref_weak_helper->target_instance = NULL;
}
The "weak" version, intrusive_weak_ptr, records the pointer to the weak helper, manipulating that reference count, and accessing the target object via the target_instance pointer. When the weak_ref_count decrements to zero the status of target_instance determines whether the helper is deleted or not.
There are many details missing (concurrency concerns for instance) but this is a mixing of the shared_ptr and the intrusive_ptr. It maintains the basic benefits of the intrusive_ptr (cache optimization, reuse of 3rd party intrusive (strong) ref count, strong and weak pointer stand-ins are pointer sized) while adding extra work mainly in the weak reference path.
Current implementation of intrusive pointer is using reference counter. So deleting object delete also delete the counter, so weak_intrusive_pointer will never know that the object was deleted.
If you need to get weak_ptr from this, you probably search boost::enable_shared_from_this<T>.
OpenSceneGraph and its successor, VulkanSceneGraph, each have comprehensive implementations of intrusive strong pointers and associated weak pointers, named ref_ptr<> and observer_ptr<>, respectively.
I don't know every detail of these systems, but it seems they work using an additional object which is informed when the referent (a descendant of the class Referenced) is deleted. Weak pointers use this third object when an attempt is made to convert them to strong pointers.
VulkanSceneGraph is the next generation scene graph that is currently in development and intended to replace OpenSceneGraph, so I assume its intrusive pointer system is a more advanced implementation.
Worth checking out:
https://github.com/vsg-dev/VulkanSceneGraph/blob/master/include/vsg/core/observer_ptr.h

How to handle 'this' pointer in constructor?

I have objects which create other child objects within their constructors, passing 'this' so the child can save a pointer back to its parent. I use boost::shared_ptr extensively in my programming as a safer alternative to std::auto_ptr or raw pointers. So the child would have code such as shared_ptr<Parent>, and boost provides the shared_from_this() method which the parent can give to the child.
My problem is that shared_from_this() cannot be used in a constructor, which isn't really a crime because 'this' should not be used in a constructor anyways unless you know what you're doing and don't mind the limitations.
Google's C++ Style Guide states that constructors should merely set member variables to their initial values. Any complex initialization should go in an explicit Init() method. This solves the 'this-in-constructor' problem as well as a few others as well.
What bothers me is that people using your code now must remember to call Init() every time they construct one of your objects. The only way I can think of to enforce this is by having an assertion that Init() has already been called at the top of every member function, but this is tedious to write and cumbersome to execute.
Are there any idioms out there that solve this problem at any step along the way?
Use a factory method to 2-phase construct & initialize your class, and then make the ctor & Init() function private. Then there's no way to create your object incorrectly. Just remember to keep the destructor public and to use a smart pointer:
#include <memory>
class BigObject
{
public:
static std::tr1::shared_ptr<BigObject> Create(int someParam)
{
std::tr1::shared_ptr<BigObject> ret(new BigObject(someParam));
ret->Init();
return ret;
}
private:
bool Init()
{
// do something to init
return true;
}
BigObject(int para)
{
}
BigObject() {}
};
int main()
{
std::tr1::shared_ptr<BigObject> obj = BigObject::Create(42);
return 0;
}
EDIT:
If you want to object to live on the stack, you can use a variant of the above pattern. As written this will create a temporary and use the copy ctor:
#include <memory>
class StackObject
{
public:
StackObject(const StackObject& rhs)
: n_(rhs.n_)
{
}
static StackObject Create(int val)
{
StackObject ret(val);
ret.Init();
return ret;
}
private:
int n_;
StackObject(int n = 0) : n_(n) {};
bool Init() { return true; }
};
int main()
{
StackObject sObj = StackObject::Create(42);
return 0;
}
Google's C++ programming guidelines have been criticized here and elsewhere again and again. And rightly so.
I use two-phase initialization only ever if it's hidden behind a wrapping class. If manually calling initialization functions would work, we'd still be programming in C and C++ with its constructors would never have been invented.
Depending on the situation, this may be a case where shared pointers don't add anything. They should be used anytime lifetime management is an issue. If the child objects lifetime is guaranteed to be shorter than that of the parent, I don't see a problem with using raw pointers. For instance, if the parent creates and deletes the child objects (and no one else does), there is no question over who should delete the child objects.
KeithB has a really good point that I would like to extend (in a sense that is not related to the question, but that will not fit in a comment):
In the specific case of the relation of an object with its subobjects the lifetimes are guaranteed: the parent object will always outlive the child object. In this case the child (member) object does not share the ownership of the parent (containing) object, and a shared_ptr should not be used. It should not be used for semantic reasons (no shared ownership at all) nor for practical reasons: you can introduce all sorts of problems: memory leaks and incorrect deletions.
To ease discussion I will use P to refer to the parent object and C to refer to the child or contained object.
If P lifetime is externally handled with a shared_ptr, then adding another shared_ptr in C to refer to P will have the effect of creating a cycle. Once you have a cycle in memory managed by reference counting you most probably have a memory leak: when the last external shared_ptr that refers to P goes out of scope, the pointer in C is still alive, so the reference count for P does not reach 0 and the object is not released, even if it is no longer accessible.
If P is handled by a different pointer then when the pointer gets deleted it will call the P destructor, that will cascade into calling the C destructor. The reference count for P in the shared_ptr that C has will reach 0 and it will trigger a double deletion.
If P has automatic storage duration, when it's destructor gets called (the object goes out of scope or the containing object destructor is called) then the shared_ptr will trigger the deletion of a block of memory that was not new-ed.
The common solution is breaking cycles with weak_ptrs, so that the child object would not keep a shared_ptr to the parent, but rather a weak_ptr. At this stage the problem is the same: to create a weak_ptr the object must already be managed by a shared_ptr, which during construction cannot happen.
Consider using either a raw pointer (handling ownership of a resource through a pointer is unsafe, but here ownership is handled externally so that is not an issue) or even a reference (which also is telling other programmers that you trust the referred object P to outlive the referring object C)
A object that requires complex construction sounds like a job for a factory.
Define an interface or an abstract class, one that cannot be constructed, plus a free-function that, possibly with parameters, returns a pointer to the interface, but behinds the scenes takes care of the complexity.
You have to think of design in terms of what the end user of your class has to do.
Do you really need to use the shared_ptr in this case? Can the child just have a pointer? After all, it's the child object, so it's owned by the parent, so couldn't it just have a normal pointer to it's parent?