Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::map thread-safety

Is reference to object in std::map is thread safe?

std::map< std::string, Object >   _objects; 

map can be changed from many threads and this access is synchronized, but reference to value (Object &) accessable just from 1 instance and thread. is write operations with Object & is safe if another thread will add items to map? will it reallocate?

like image 420
deeptowncitizen Avatar asked Feb 25 '13 12:02

deeptowncitizen


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 reading from a map thread-safe C++?

The map you use is immutable de facto so any find will actually do a find in a map which does not change. 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.

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.

Is std :: function thread-safe?

Calling the function it points to is as thread-safe as the code being called; no more, and no less. And even if you make a copy in the first case, you still need protection, so long as there is a potential writer somewhere in the mix.


2 Answers

The C++11 standard guarantees that const method access to containers is safe from different threads (ie, both use const methods).

In addition, [container.requirements.dataraces] states

implementations are required to avoid data races when the contents of the contained object in different elements in the same sequence, excepting vector<bool>

In other words, except for vector<bool> modifying distinct contents is not a data race.

Now, if one thread invalidates an iterator used by another thread, clearly this is a data race (and results in undefined behavior). If one thread does non-const access to a container, and another does const access, that is a data race (and undefined behavior). (Note: a number of functions are "considered const" for the purpose of multithreading, including begin, end and other functions (and methods) that are non-const simply because they return non-const iterators. [] is included in this set of pseudo-const for thread safety reasons, except for map and unordered_set etc -- 23.2.2.1).

However, it appears that if you have a reference to an element within the container, and engage in operations that do not invalidate that reference in another thread, and never write to that element in another thread, you can safely read from that reference. Similarly, if other threads never even read from the element, then writing to that element shouldn't result in undefined behavior.

For standards references, 17.6.5.9.5 seems to guarantee that functions from the standard library won't run away and read/write elements needlessly.

So the short answer: you are safe, so long as the other thread doesn't directly mess with that particular entry in the map.

like image 198
Yakk - Adam Nevraumont Avatar answered Oct 01 '22 20:10

Yakk - Adam Nevraumont


Elements in a map are stable, they do not get moved or invalidated unless the element is erased from the map. If only one thread is writing to a given object, and changes to the map itself are correctly synchronized, then I believe it will be safe. I'm sure it's safe in practice, and I think it's safe in theory too.

The standard guarantees that distinct elements can be modified by different threads, in [container.requirements.dataraces]

Notwithstanding (17.6.5.9), implementations are required to avoid data races when the contents of the contained object in different elements in the same sequence, excepting vector<bool>, are modified concurrently.

This only allows you to modify the elements, not to insert new elements into the map while modifying elements. For some containers, such as std::vector, modifying the vector itself might also modify elements by reallocating and moving them, but [associative.reqmts]/9 ensures std::map won't invalidate existing elements.

Since no member function of std::map is required to access the second member of its elements (i.e. the mapped_type) I think [res.on.data.races]/5 says no other thread will conflict with writes to that member when modifying the map. (Thanks to Yakk for that final piece of the puzzle)

like image 38
Jonathan Wakely Avatar answered Oct 01 '22 20:10

Jonathan Wakely