4

I have an STL map that will be accessed by two threads. Neither of them inserts nor removes elements: they just read.

If it were just a simple array, I am sure that this would never cause trouble. However, the STL map is a complicated data structure whose implementation is unknown to me. Will this cause a data race?

cpp_noname
  • 2,031
  • 3
  • 17
  • 30

1 Answers1

2

Standard C++ containers (as of 2011) allow safe access by multiple concurrent readers (i.e. via const member functions).

That is, you are ok (assuming the const member functions on the types you are using with the container follow the same rules: bitwise-const except on objects that are protected from access by other threads).

If you are using an old implementation you may in theory have problems, but I doubt it.

Here's an entire chunk of the Library introduction section of The Standard (N3337). I don't think any one of these paragraphs alone is enough to answer your question, so you get the whole lot!

17.6.5.9 Data race avoidance [res.on.data.races]

1 This section specifies requirements that implementations shall meet to prevent data races (1.10). Every standard library function shall meet each requirement unless otherwise specified. Implementations may prevent data races in cases other than those specified below.

2 A C++ standard library function shall not directly or indirectly access objects (1.10) accessible by threads other than the current thread unless the objects are accessed directly or indirectly via the function’s arguments, including this.

3 A C++ standard library function shall not directly or indirectly modify objects (1.10) accessible by threads other than the current thread unless the objects are accessed directly or indirectly via the function’s non-const arguments, including this.

4 [ Note: This means, for example, that implementations can’t use a static object for internal purposes without synchronization because it could cause a data race even in programs that do not explicitly share objects between threads. —end note ]

5 A C++ standard library function shall not access objects indirectly accessible via its arguments or via elements of its container arguments except by invoking functions required by its specification on those container elements.

6 Operations on iterators obtained by calling a standard library container or string member function may access the underlying container, but shall not modify it. [ Note: In particular, container operations that invalidate iterators conflict with operations on iterators associated with that container. —end note ]

7 Implementations may share their own internal objects between threads if the objects are not visible to users and are protected against data races.

8 Unless otherwise specified, C++ standard library functions shall perform all operations solely within the current thread if those operations have effects that are visible (1.10) to users.

9 [ Note: This allows implementations to parallelize operations if there are no visible side effects. —end note ]

BoBTFish
  • 19,167
  • 3
  • 49
  • 76
  • As long as only const members are used, and the values adhere to the same (const members cannot alter anything _at the bit level_; only exemption: thread primitives like `std::mutex`) – sehe Sep 25 '13 at 09:31
  • According to http://www.cplusplus.com/reference/map/map/begin there are different versions of begin: (1) iterator begin() (2) const_iterator begin() const: My question is "how do I know which one will be used"? – cpp_noname Sep 25 '13 at 09:40
  • @takwing Iff you have a `const` object, you get the `const` version. However, if you specifically know you want `const_iterator`s and don't care about the `const`ness of the `map` in your context use the [`cbegin`](http://en.cppreference.com/w/cpp/container/map/begin) and [`cend`](http://en.cppreference.com/w/cpp/container/map/end) member functions. – BoBTFish Sep 25 '13 at 09:47
  • @BoBTFish, by const object, does it mean that the values in the entries are of a const type? – cpp_noname Sep 25 '13 at 09:51
  • @takwing I mean if the `map` itself is `const`, then `myMap.begin()` will return a `const_iterator`. The `map` may be `const` for various reasons, including: 1) it was declared that way: `const std::map myMap;` (of limited use). 2) it is accessed as a member of a `const` class instance: `const MyClass myInstance; myInstance.mapMember_.begin();`. 3) you access a member of some class inside a `const` member function (this is basically 2): `void myClass::foo() const { mapMember_.begin(); }`. – BoBTFish Sep 25 '13 at 09:58