I use std::map
and to get a single element I can use: http://www.cplusplus.com/reference/map/map/
iterator find (const key_type& k);
mapped_type& at (const key_type& k);
mapped_type& operator[] (const key_type& k);
also: lower_bound()
or equal_range()
- are same as find()
in this case.
I can't use:
at()
- because it throw an exception, and I measured 10 times the performance degradationoperator[]
- because it insert an element if it non-exist, such behavior is unacceptablefind()
- is what I want. But I use std::map
in multi-thread program and protect it by lock std::mutex
.
There are also insertion and removal to std::map
from the other threads.
Should I protect std::map::end
or is guaranteed that it always the same for one allocated container?
Can I use something like this static auto const map_it_end = map1.end();
which is not protected by std::mutex
?
http://ideone.com/tATn0H
#include <iostream>
#include <string>
#include <mutex>
#include <thread>
#include <map>
std::map<std::string, std::string> map1 ( {{"apple","red"},{"lemon","yellow"}} );
static auto const map_it_end = map1.end();
std::mutex mtx1;
void func() {
std::lock_guard<std::mutex> lock1(mtx1);
auto it1 = map1.find("apple");
if(it1 != map_it_end) // instead of: if(it1 != map1.end())
std::cout << it1->second << ", ";
}
int main ()
{
std::thread t1(func);
std::thread t2(func);
t1.join();
t2.join();
return 0;
}
http://www.cplusplus.com/reference/map/map/end/
Data races The container is accessed (neither the const nor the non-const versions modify the container). No contained elements are accessed by the call, but the iterator returned can be used to access or modify elements. Concurrently accessing or modifying different elements is safe.
It isn't thread safe, insert from two threads and you can end up in an inconstant state.
It is inherently thread-safe. There are no data races on concurrent memory reads. However, you must guarantee safe initializations by only a single thread. As Max S.
std::map is a sorted associative container that contains key-value pairs with unique keys. Keys are sorted by using the comparison function Compare . Search, removal, and insertion operations have logarithmic complexity. Maps are usually implemented as red-black trees.
The SGI implementation of STL is thread-safe only in the sense that simultaneous accesses to distinct containers are safe, and simultaneous read accesses to to shared containers are safe.
Should I protect
std::map::end
or is guaranteed that it always the same for one allocated container?
Technically any call to a member function must be protected by a mutex if it could happen concurrently with any non-const member function. So if any thread could be inserting or erasing elements then it's not safe to call end()
without locking the mutex.
Can I use something like this
static auto const map_it_end = map1.end();
which is not protected bystd::mutex
?
You can cache the past-the-end iterator in some cases, because the past-the-end iterator for a std::map
is not invalidated by insertions and erasures, only potentially by swapping or moving the map.
But why would you want to? The slow operation is find()
not end()
, so if you call end()
while you still hold the mutex then it definitely works.
If other threads could be erasing elements then you need to hold the mutex lock while you dereference the iterator returned by find()
to be sure it isn't invalidated by another thread erasing the element it refers to. So again, making a call to end()
isn't going to be a problem while you have the mutex locked already.
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