c++multithreadingdictionaryatomicstdatomic

Is std::atomic<std::map<S, T>> thread-safe for reading and writing?


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?


Solution

  • 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.