Warning: mysqli::__construct(): (HY000/1203): User howardkn already has more than 'max_user_connections' active connections in D:\Inetpub\vhosts\howardknight.net\al.howardknight.net\includes\artfuncs.php on line 21
Failed to connect to MySQL: (1203) User howardkn already has more than 'max_user_connections' active connections
Warning: mysqli::query(): Couldn't fetch mysqli in D:\Inetpub\vhosts\howardknight.net\al.howardknight.net\index.php on line 66
Article <vca82m$32puo$1@dont-email.me>
Deutsch   English   Français   Italiano  
<vca82m$32puo$1@dont-email.me>

View for Bookmarking (what is this?)
Look up another Usenet article

Path: ...!news.mixmin.net!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: Paavo Helde <eesnimi@osa.pri.ee>
Newsgroups: comp.lang.c++
Subject: Re: Atomic caching of smart pointers
Date: Tue, 17 Sep 2024 00:31:02 +0300
Organization: A noiseless patient Spider
Lines: 112
Message-ID: <vca82m$32puo$1@dont-email.me>
References: <vc7ahq$2akr4$1@dont-email.me> <vc7f5o$2atht$5@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit
Injection-Date: Mon, 16 Sep 2024 23:31:02 +0200 (CEST)
Injection-Info: dont-email.me; posting-host="25c001b34953d8924566cc4a0ce3aa9f";
	logging-data="3237848"; mail-complaints-to="abuse@eternal-september.org";	posting-account="U2FsdGVkX1/tV2coDfEAnXc5co/TPoeyfUiLYVxJQ+U="
User-Agent: Mozilla Thunderbird
Cancel-Lock: sha1:4HdvxLi8GKtY7zOUJtlt80JWMH0=
Content-Language: en-US
In-Reply-To: <vc7f5o$2atht$5@dont-email.me>
Bytes: 5438

On 15.09.2024 23:13, Chris M. Thomasson wrote:
> 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);
>>          }
>>      }
>>
>>      /// Return pointer stored in *this,
>>      Ptr<T> Load() const {
>>          return Ptr<T>(ptr_);
>>      }
>>
>>      ~CachedAtomicPtr() {
>>          if (const T* ptr = ptr_) {
>>              ptr->DecrementRefcount();
>>          }
>>      }
>> private:
>>      std::atomic<const T*> ptr_;
>> };
>>
>> Example usage:
>>
>> /// Objects of this class are in shared use by multiple threads.
>> class A {
>>      // Returns B corresponding to the value of *this.
>>      // If not yet in cache, B is calculated and cached in *this.
>>      // Calculating can happen in multiple threads in parallel,
>>      // the first cached result will be used in all threads.
>>      Ptr<B> GetOrCalcB() const {
>>          Ptr<B> b = cached_.Load();
>>          if (!b) {
>>              b = cached_.AssignIfNull(CalcB());
>>          }
>>          return b;
>>      }
>>      // ...
>> private:
>>      // Calculates cached B object according to value of *this.
>>      Ptr<B> CalcB() const;
>> private:
>>      mutable CachedAtomicPtr<B> cached_;
>>      // ... own data ...
>> };
>>
>> So, what do you think? Should I just use std::atomic<std::shared_ptr> 
>> instead? Any other suggestions? Did I get the memory order parameters 
>> right in compare_exchange_weak()?
>>
> 
> I need to look at this when I get some time. Been very busy lately. 
> Humm... Perhaps, when you get some free time to burn... Try to model it 
> in Relacy and see what happens:
> 
> https://www.1024cores.net/home/relacy-race-detector/rrd-introduction
> 
> https://groups.google.com/g/relacy
> 


Took a look at that. It appears for using Relacy I have to somehow 
translate my algorithm into Relacy-language, but this seems non-trivial. 
There is about zero documentation and zero code comments, and examples 
are not compiling with VS2022. Looks like for using it I would need to 
grow some 20 extra IQ points and spend a significant amount of time.