I have a C++11 program that does some computations and uses a std::unordered_map
to cache results of those computations. The program uses multiple threads and they use a shared unordered_map
to store and share the results of the computations.
Based on my reading of unordered_map
and STL container specs, as well as unordered_map thread safety, it seems that an unordered_map
, shared by multiple threads, can handle one thread writing at a time, but many readers at a time.
Therefore, I'm using a std::mutex
to wrap my insert()
calls to the map, so that at most only one thread is inserting at a time.
However, my find()
calls do not have a mutex as, from my reading, it seems that many threads should be able to read at once. However, I'm occasionally getting data races (as detected by TSAN), manifesting themselves in a SEGV. The data race clearly points to the insert()
and find()
calls that I mentioned above.
When I wrap the find()
calls in a mutex, the problem goes away. However, I don't want to serialize the concurrent reads, as I'm trying to make this program as fast as possible. (FYI: I'm running using gcc 5.4.)
Why is this happening? Is my understanding of the concurrency guarantees of std::unordered_map
incorrect?
You still need a mutex
for your readers to keep the writers out, but you need a shared one. C++14
has a std::shared_timed_mutex that you can use along with scoped locks std::unique_lock and std::shared_lock like this:
using mutex_type = std::shared_timed_mutex;
using read_only_lock = std::shared_lock<mutex_type>;
using updatable_lock = std::unique_lock<mutex_type>;
mutex_type mtx;
std::unordered_map<int, std::string> m;
// code to update map
{
updatable_lock lock(mtx);
m[1] = "one";
}
// code to read from map
{
read_only_lock lock(mtx);
std::cout << m[1] << '\n';
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With