I have an object that stores some settings in an unordered_map
with string keys and variant values. As my library might be used from several threads and reads will very likely outnumber writes by a large margin, I've thought about a copy on write implementation where the "get" operation is lock free and the "put" operation is in a critical section, as in the example:
class Cfg {
using M = unordered_map<string,X>;
shared_ptr<const M> data;
mutex write_lock;
public:
X get(string key) {
shared_ptr<const M> cur_ver = atomic_load_explicit(&data, memory_order_acquire);
// Extract the value from the immutable *cur_ver
}
void put(string key, X value) {
lock<muted> wlock(write_lock);
// No need for the atomic load here because of the lock
shared_ptr<const M> cur_ver = data;
shared_ptr<const M> new_ver = ;// create new map with value included
// QUESTION: do I need this store to be atomic? Is it even enough?
atomic_store_explicit(&data, new_ver, memory_order_release);
}
}
I am reasonably confident that the design works, as long as the acquire/release synchronization affects also the pointed-to data and not just the pointer value. However, my questions are as follows:
- Is the atomic store within the lock required for this to work?
- Or will the atomic acquire synchronize with the mutex unlock which is a "release" operation?