Liste des Groupes | Revenir à cl c++ |
On 9/16/2024 2:31 PM, Paavo Helde wrote:Correct. The `p->IncrementRefcount();` line will keep the assigned T object alive, regardless of how many other smartpointers there are pointing to it in any threads. The refcount is decremented in ~CachedAtomicPtr().On 15.09.2024 23:13, Chris M. Thomasson wrote:So as long as CachedAtomicPtr is alive, the cached pointer, the one that gets installed in your AssignIfNull function, will be alive?On 9/15/2024 11:54 AM, Paavo Helde wrote:>
I am thinking of developing some lock-free data structures for better scaling on multi-core hardware and avoiding potential deadlocks. In particular, I have got a lot of classes which are mostly immutable after construction, except for some cached data members which are calculated on demand only, then stored in the object for later use.
>
Caching single numeric values is easy. However, some cached data is large and accessed via a std::shared_ptr type refcounted smartpointers. Updating such a smartpointer in a thread-shared object is a bit more tricky. There is a std::atomic<std::shared_ptr> in C+ +20, but I wonder if I can do a bit better by providing my own implementation which uses CAS on a single pointer (instead of DCAS with additional data fields or other trickery).
>
This is assuming that
>
a) the cached value will not change any more after assigned, and will stay intact until the containing object destruction;
>
b) it's ok if multiple threads calculate the value at the same time; the first one stored will be the one which gets used.
>
My current prototype code is as follows (Ptr<T> is similar to std::shared_ptr<T>, but is using an internal atomic refcounter; using an internal counter allows me to generate additional smartpointers from a raw pointer).
>
template<typename T>
class CachedAtomicPtr {
public:
CachedAtomicPtr(): ptr_(nullptr) {}
>
/// Store p in *this if *this is not yet assigned.
/// Return pointer stored in *this, which can be \a p or not.
Ptr<T> AssignIfNull(Ptr<T> p) {
const T* other = nullptr;
if (ptr_.compare_exchange_weak(other, p.get(), std::memory_order_release, std::memory_order_acquire)) {
p->IncrementRefcount();
return p;
} else {
// wrap in an extra smartptr (increments refcount)
return Ptr<T>(other);
}
}
Sorry if my question sounds stupid or something. Get trying to get a handle on your usage pattern. Also, the first pointer installed in CachedAtomicPtr will remain that way for the entire duration of the lifetime of said CachedAtomicPtr instance?Correct. Otherwise I would need a mutex, DCAS or some other trickery for avoiding races.
Les messages affichés proviennent d'usenet.