I've a std::map<std::string, std::tuple<int, int, std::atomic<int>>> mp. The map can be read and write parallel so I use a read-write lock to keep it thread safe.
I want to know if I can write std::get<2>(mp["someKey"]) in the read lock area.
void read() {
// read lock area
std::shared_lock<std::shared_mutex> read_lock{mtx};
// "someKey" exists already
std::get<2>(mp["someKey"]).store(2);
}
I've tried to do some tests, it seems that it works but I don't know if it's incorrect and gives me a coredump someday.
Firstly, note that
mp["someKey"]modifies the map and is not thread-safe. If no key exists yet,operator[]will create a new value-initialized key/value pair. See also Why is std::map::operator[] considered bad practice?Instead, you should use
mp.at("someKey")ormp.find("someKey"):.store(2);is thread-safe because writing to astd::atomicfrom multiple threads simultaneously is safe. Thestd::shared_lockisn't necessary to ensure this. However, thestd::shared_lockensures that the surroundingstd::paircannot be destroyed by another thread so it must be kept.Note on const-correctness
Const-correctness would have prevented the bug with
mp["someKey"]. If you only hold a read-lock, it's good practice to work with aconst&to prevent accidental modifications:Note on
std::tuplestd::tupleoutside of variadic templates is always questionable. It's almost always better to have meaningful names: