The get function always returns you a stable value if at least one value was ever written (else you get NULL, natch).
The set function will not invalidate any values seen by get that might still be referenced, but the new value will be seen by all subsequent gets.
Old values will be destructed when no longer referenced.
To read-copy-update you'll need to take a lock (that readers don't), get the current value (it will be the current one given you're locking out other writers), copy it, modify the copy, then set the new value.
You don't have to read-copy-update if the new values don't depend on the preceding values. So my API does not force read-copy-update, but you can do RCU with it.
Got it. So basically you want writers to use their own lock to coordinate writes. Okay, then this makes it inconvenient to deal with readers that could possibly but infrequently become writers. They have to do a second read under a lock to write. And if one chooses a data structure for which copy isn't a cheap operation, this can be slower than classic RCU.
> Okay, then this makes it inconvenient to deal with readers that could possibly but infrequently become writers. They have to do a second read under a lock to write.
Well, first of all reads are real cheap, so that's not a big concern. In some systems readers don't ever turn around to write, so that's ok, and in others they don't modify the current value. E.g., in one system I've built we use TinyCDB files and when new files are renamed into place we open those and set the handle on one of these thread-safe variables -- no read-modify involved here.
> And if one chooses a data structure for which copy isn't a cheap operation, this can be slower than classic RCU.
Either way it's RCU. It's best to publish immutable data with RCU and design data structures where copy-on-write modifications don't have to copy the whole data structure but rather just small parts of it. E.g., in a tree you should only have to copy the interior nodes from the one you're modifying to the root.
One can always build a hash table where each cell is one of these thread-safe variables (or plain old RCU), though one would have to make these thread-safe variables lighter weight to make having lots of them realistic (currently my implementation has a pthread_key_t per variable, which does not scale).
In TFA ArcSwap is essentially indistinguishable from a read-only hash table published on something like one of my thread-safe variables, and for TFA this worked better than the available alternatives in spite of the copy-on-write burden.
BTW, I built this thing originally to allow global configuration to be shared with otherwise-shared-nothing threads and allow the service to be reconfigurable at run-time. Without something like this (or plain old RCU) your options are limited to things like using read-write locks (which are way worse than anything you can imagine being bad about RCU used with immutable data structures). I was very displeased with read-write locks when I needed to solve this particular problem at Sun, but I didn't build this thing until after I left Sun (Oracle).
Nowadays RCU-ish libraries are pretty widely available. OpenSSL 3.3 (or was it 3.4?) has something like this after the threaded performance debacles of 3.0. In particular OpenSSL has an RCU-ish hash table. You might be interested in it. IIRC (but it's been a while since I looked) it uses one hazard-pointer-per-thread to acquire a stable reference to a key or value long enough to then incref a refcount -- pretty clever, and that's essentially the way to make a "thread-safe variable" light-weight enough to be able to use one for each slot in a hash table.
The set function will not invalidate any values seen by get that might still be referenced, but the new value will be seen by all subsequent gets.
Old values will be destructed when no longer referenced.
To read-copy-update you'll need to take a lock (that readers don't), get the current value (it will be the current one given you're locking out other writers), copy it, modify the copy, then set the new value.
You don't have to read-copy-update if the new values don't depend on the preceding values. So my API does not force read-copy-update, but you can do RCU with it.