Boost logo

Boost :

Subject: Re: [boost] [atomic] Generalized read-modify-write operation
From: Andrey Semashev (andrey.semashev_at_[hidden])
Date: 2015-09-01 20:11:48


On 02.09.2015 02:20, Gavin Lambert wrote:
> On 1/09/2015 21:35, Andrey Semashev wrote:
>> I was wondering is there would be interest in a generalized
>> read-modify-write operation in Boost.Atomic. The idea is to have a
>> atomic<T>::read_modify_write method that would take a function that
>> would perform the modify on the atomic value. The interface could be
>> roughly this:
> [...]
>> Does this look interesting to anyone? Comments?
>
> It's not strictly necessary since it's equivalent to a do { r =
> modify(n); } while (!var.compare_exchange_weak(n, r, order)) loop, which
> isn't that much more typing. (Although I elided the initial load, so
> it's a bit more typing than it appears here.)

Yes, correct. r and n also have to be declared outside the loop, which
is kind of annoying.

> (And the above is also supposed to use LL/SC on architectures where this
> is cheaper than CAS, although I'm not sure if this is the case.)

I'm not sure there are architectures that implement both CAS and LL/SC
instructions, at least I'm not aware of such. On the architectures that
support LL/SC, the instructions will be used to implement
compare_exchange_weak. The modify function in this CAS loop will not be
executed within the LL/SC region, which is why the additional load
before the loop is required. There is also a probability of CAS failure.

There is another point to consider. compare_exchange_weak/strong
opereation on an LL/SC architecure is more complex than what is required
to implement a simple RMW operation. For example, let's see it in
Boost.Atomic code for ARM. Here is fetch_add, which can be used as a
prototype of what could be done with a generic RMW operation:

   "1:\n"
   "ldrex %[original], %[storage]\n"
   "add %[result], %[original], %[value]\n" // modify
   "strex %[tmp], %[result], %[storage]\n"
   "teq %[tmp], #0\n"
   "bne 1b\n"

Frankly, I'd like to be able to generate code like this for operations
other than those defined by the standard atomic<> interface.

And here is CAS (weak):

   "mov %[success], #0\n"
   "ldrex %[original], %[storage]\n"
   "cmp %[original], %[expected]\n"
   "itt eq\n"
   "strexeq %[success], %[desired], %[storage]\n"
   "eoreq %[success], %[success], #1\n"

To this we will also have to add the load, the modify and the loop.

> But provided that the code generated is no worse than this (in
> particular that the compiler can inline the function call in optimised
> builds, at least where the function is relatively simple) then it would
> still be useful, particularly for people who aren't used to using weak
> exchange loops.

I certainly hope the compiler will be able to inline the modify
function. If it doesn't, for relatively simple functions, then it
probably isn't worth it.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk