C++11 STL containers and thread safety

41,030

Solution 1

Since the existing answers don't cover it (only a comment does), I'll just mention 23.2.2 [container.requirements.dataraces] of the current C++ standard specification which says:

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.

i.e. it's safe to access distinct elements of the same container, so for example you can have a global std::vector<std::future<int>> of ten elements and have ten threads which each write to a different element of the vector.

Apart from that, the same rules apply to containers as for the rest of the standard library (see 17.6.5.9 [res.on.data.races]), as Mr.C64's answer says, and additionally [container.requirements.dataraces] lists some non-const member functions of containers that can be called safely because they only return non-const references to elements, they don't actually modify anything (in general any non-const member function must be considered a modification.)

Solution 2

I think STL containers offer the following basic thread-safety guarantee:

  • simultaneous reads of the same object are OK

  • simultaneous read/writes of different objects are OK

But you have to use some form of custom synchronization (e.g. critical section) if you want to do something different, like e.g. simultaneous writes on the same object.

Share:
41,030

Related videos on Youtube

Šimon Tóth
Author by

Šimon Tóth

Backend oriented Software developer and Researcher with industry experience starting in 2004.

Updated on July 09, 2022

Comments

  • Šimon Tóth
    Šimon Tóth almost 2 years

    I have trouble finding any up-to-date information on this.

    Do C++11 versions of STL containers have some level of thread safety guaranteed?

    I do expect that they don't, due to performance reasons. But then again, that's why we have both std::vector::operator[] and std::vector::at.

    • Constantinius
      Constantinius over 11 years
      My guess is, that bounds checking is on a totally different performance scale than mutexes or the like. Could be wrong though.
    • jcoder
      jcoder over 11 years
      Thread safety at the level of container access is often useless as you want to write things like "cash[i] = cash[i] + total" and the locking needs to be at a higher level than on the container itsself.
    • Bo Persson
      Bo Persson over 11 years
    • avakar
      avakar over 11 years
      There are quite a few guarantees (sections [res.on.data.races], [container.requirements.dataraces] and of course the prerequisite [intro.multithread]). @Mr.C64's answer is very much to the point, if you want a more specific answer (possibly with standard quotes), please adjust the question.
    • Šimon Tóth
      Šimon Tóth over 11 years
      @avakar It would be great if you could make an answer for quotes. I have the standard, but It would be nice to close the question an exhaustive answer.
  • Šimon Tóth
    Šimon Tóth over 11 years
    What is the meaning of "object" in this context? Element or container?
  • Steve Jessop
    Steve Jessop over 11 years
    For example, is it OK to execute myvec[0] = 0 and myvec[1] "simultaneously" in different threads? If the "object" is the container then that's a read and a write to the same object, but if the "object" is the element then it isn't. You can also imagine a container like a splay tree in which simultaneous reads to the container are not OK, but presumably if there's a guarantee that simultaneous reads are OK then it is forbidden for std::map to be implemented as a splay tree that's unsafe in that respect.
  • Mr.C64
    Mr.C64 over 11 years
    @Let_Me_Be: "object" == container in this case.
  • avakar
    avakar over 11 years
    @SteveJessop, myvec[0] = 0 while simultaneously myvec[1] is OK -- operator[] on sequential containers must avoid races ([container.requirements.dataraces]/1). This is not true for unordered and associative containers.
  • Jonathan Wakely
    Jonathan Wakely over 11 years
    @avakar, I believe that requirement applies to all standard containers, not just the sequence containers. I'll request a new issue to clarify the wording.
  • avakar
    avakar over 11 years
    @JonathanWakely, I'm basing this on n3337/23.2.2/1: "For purposes of avoiding data races (17.6.5.9), implementations shall consider the following functions to be const: begin, end, [...] and, except in associative or unordered associative containers, operator[]."
  • avakar
    avakar over 11 years
    @JonathanWakely, if you already have a valid pointer/reference to the elements, you can read them simultaneously. The data race could occur in the invocation of [] on the same container.
  • Jonathan Wakely
    Jonathan Wakely over 11 years
    @avakar, Ah, sorry, I thought you meant §2 where it says "sequence", I think that requirement applies to all containers. If you already have a valid reference to the elements you can write to them simultaneously iff they're different elements.
  • Nicol Bolas
    Nicol Bolas over 11 years
    "but that is even pre C++11" No it isn't. C++03 doesn't even know what threading is. So it does not specify behavior dealing with threading.
  • Nicol Bolas
    Nicol Bolas over 11 years
    He didn't ask how compilers implement the standard. He what guarantees the standard provided; "guarantees" that implementations provide are therefore irrelevant.
  • NoSenseEtAl
    NoSenseEtAl over 11 years
    that is your opinion, OP doesnt specifies that he is interested in just the standard and not reality. But it is pointless discussion since first 2 chars of my answer are the most important part. Rest of the importance mostly lies in second sentence. :)
  • Christian Rau
    Christian Rau over 11 years
    @NoSenseEtAl And in fact those "first 2 chars" that "are the most important part" are wrong, since the other answers have clearly shown that the there is indeed some level of thread-safety guaranteed, be it only for simultaneous reads without any writes, or certain functions. So a definite "No" is just too general to be correct in any way.
  • NoSenseEtAl
    NoSenseEtAl over 11 years
    I dont consider that multiple readers is noteworthy(though I added that long time before ppl complained in the comments so that ppl dont get confused). Then again maybe Im not like average dev( In a sense that I see read safety as trivial - see my first comment)
  • Nicol Bolas
    Nicol Bolas over 11 years
    @NoSenseEtAl: "I dont consider that multiple readers is noteworthy" But he didn't ask what you considered noteworthy. He asked for facts: "Do C++11 versions of STL containers have some level of thread safety guaranteed?" The factual answer is "Yes," because the standard does have some level of guarantees.