Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is std::map::end thread-safe and is guaranteed that it always the same for the same container?

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 degradation
  • operator[] - because it insert an element if it non-exist, such behavior is unacceptable

find() - 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.

like image 853
Alex Avatar asked Jul 05 '16 23:07

Alex


People also ask

Are std::map thread-safe?

It isn't thread safe, insert from two threads and you can end up in an inconstant state.

Is std :: max thread-safe?

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.

What is std::map used for?

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.

Is STL thread-safe?

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.


1 Answers

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 by std::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.

like image 187
Jonathan Wakely Avatar answered Oct 21 '22 02:10

Jonathan Wakely