Is Stl Vector Concurrent Read Thread-Safe

Is stl vector concurrent read thread-safe?

YES for the scenario you mention, it is perfectly Thread Safe.


Actually, STL is not a correct way of referring it.

It is the C++ Standard Library.

The C++03 Standard does not talk about concurrency at all, So the concurrency aspect is left out as an implementation detail for compilers. So the documentation that comes with your compiler is where one should look to for answers related to concurrency.

Most of the STL implementations are not thread safe as such.

But for concurrent reads of same object from multiple threads most implementations of STL are indeed thread safe.

References:

MSDN says:

A single object is thread safe for reading from multiple threads. For example, given an object A, it is safe to read A from thread 1 and from thread 2 simultaneously.

The Dinkumware STL-Documentation says:

Multiple threads can safely read the same container object. (There are nunprotected mutable subobjects within a container object.)

GCC Documentation says:

We currently use the SGI STL definition of thread safety, which states:

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. If multiple threads access a single container, and at least one thread may potentially write, then the user is responsible for ensuring mutual exclusion between the threads during the container accesses.

So from the above, Yes it is thread safe in GCC to have concurrent reads of same object from multiple threads.

Note: GCC's Standard Library is a derivative of SGI's STL code.

Is std::vector thread-safe and concurrent by default? Why or why not?

C++11 says the following about the thread safetly of containers in the standard library:

23.2.2 Container data races [container.requirements.dataraces]

For purposes of avoiding data races (17.6.5.9), implementations shall
consider the following functions to be const: begin, end,
rbegin, rend, front, back, data, find, lower_bound,
upper_bound, equal_range, at and, except in associative or
unordered associative containers, operator[].

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.

So, basically reading from a container from multiple threads is fine, and modifying elements that are already in the container is fine (as long as they are different elements).

So, neither of your two more specific questions are thread safe for std::vector:

1) Two threads inserting into the vector is modifying the vector itself - not existing separate elements.

2) One thread erasing and other walking to access the same element is not safe because erasing an element from the vector isn't an operation that is promised to be thread safe (or "free from data races", as the standard puts it).

To perform those operations safely will require that the program impose some external synchronization itself.

Are std::vectors threadsafe?

If you have setup the vector before entering into multi-threading scenario, and then you want to only read the vector from multiple threads, without modifying it, then it is thread-safe. You can read even the same element from more than two threads simultaneously, just make sure that no thread modifies the vector in any way. Treat the vector and all its elements as read-only.

However, for modification, none of the containers from the Standard Library are thread-safe. You need to implement the synchronization yourself.

C++11 has introduced many synchronization primitives, so if your compiler supports, you can use them.

Container Thread Safety

The main thread-safety rule of stl containers is that if more than one working thread is accessing a shared container, and at least one of them is non-const, then the threads should be synchronized. If you do not put any synchronizations, it will be undefined behavior.

if you take a look at the C++ reference here for std::vector::size(), it says:

Data Races

The container is accessed. No contained elements are accessed:
concurrently accessing or modifying them is safe.

As mentioned, the vector container will be accessed during the call to .size() and this access does not allow you to call non-const methods at the same time on the vector. If you push_back an element into the vector when you get the size of the vector by calling .size(), then the behavior of your program will be undefined.

std::vector, thread-safety, multi-threading

Actually, it is absolutely pointless to state X is or is not thread-safe! You need to qualify for what kind of uses. For example, hardly any class will be "thread-safe" when it is somehow used in one thread and destroyed in another.

That said, the statement that std::vector<T> is not thread- safe, independent of how often it is repeated, is wrong. However, it seems most people neither understand nor appreciate the thread-safety guarantees given. std::vector<T> is thread-safe in the following sense:

  • You can read a vector object from multiple threads simultaneously.
  • If there is one thread changing a vector object, there shall be neither concurrent readers or writers.
  • Accesses to a vector object don't interfere with other vector objects.

This applies to vector structure itself. Accesses to contained object are bound to whatever rules are imposed on them. These are apparently not the thread-safety guarantees many people have in mind but anything stronger won't work with the container interface.

Efficiency of concurrent std::vector writes

Yes it is safe, standard requires it to be safe. However, it might be inefficient due to what is called 'false sharing'.

False sharing happens when to individual threads update adjacent memory, which belongs to the same cache line. If those threads happen to be executed on two different cores, they end up invalidating the cache line on both CPUs and trigger expensive cache updates.

Code writer should make reasonable efforts to make the false sharing less likely by trying to assign close indexes to the same thread.

And to answer question I have just seen in the original post - no, there will be no compiler-generated fences on such writes.



Related Topics



Leave a reply



Submit