Suppose I have a std::atomic<std::map<std::string, std::string>>
and different threads do operations like std::string foo = map["bar"];
and map["bar"] = "baz"
. I don't save references or pointers to the values in the map. I just need storing and retrieving values to happen thread-safely. Does this work, or do I need to use a lock or such?
There is no std::atomic<std::map<S, T>>
, hence it cannot be thread-safe to read or write from it. But let's go a step back and consider what std::atomic
gives us.
Generally std::atomic<T>
allows to load and store the value as a whole in a thread-safe way. Load and store are each atomic. No other thread can interfere with a load
nor a store
.
However, calling operator[]
on a std::map
is not just a store nor a load. Ergo atomic access to the map as a whole is not sufficient.
Here
std::map<std::string,std::string> x;
std::string foo = x["bar"];
the second line looks up the value in the map for the given key, if no value exists it inserts one, then it returns a reference to the mapped value. std::atomic::load
returns a copy, hence a wrong (!) implementation of the semantics of operator[]
in terms of load
and store
would be
auto m = map.load();
std::string foo = m["bar"];
map.store(foo);
While the load
and the store
individually are atomic and thread-safe, the operation as a whole is not. std::atomic
simply does not help here.
Last but not least, std::atomic<T>
requires T
to be TriviallyCopyable, but a std::map
is not TriviallyCopyable.