I have a std::vector<std::atomic<size_t>> vec. Is it safe to run vec[index].fetch_add(1, std::memory_order_release) or store/load with multiple concurrent threads on it? I think it should be, because reading is thread safe and writing to one entry at the same time from multiple threads is impossible because of the atomics - is that right?
No it is not, in general, thread safe since the container itself is not atomic.
That said, so long as you don't change what is in the vector (i.e. doing anything that invalidates the return of data()) , you'll be fine.
Sadly you can't resort to std::atomic<std::vector<...>> as a std::vector is not trivially copyable.
vec[X].fetch_add is safe as long as you're modifying each individual atomic. If you call any non-const (modifying) method of the wrapping std::vector this is undefined behaviour, as std::vector itself is not thread safe.
De-facto, you can initialize the vector in some thread, pass its reference to some asynchronous task and from that point, only act on specific elements of the vector, not act on the vector itself. vec[X].action(...) is thread safe, vec.action(...) is not.
It depends what the other threads are doing.
From the standard:
17.6.5.9 Data race avoidance [res.on.data.races]
...
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.
and
23.2.2 Container data races [container.requirements.dataraces]
1 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[].
2 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 container, excepting vector<bool>, are modified concurrently.
By combining these two parts with the rules for atomics, we can deduce that calling vec[index].fetch_add(1, std::memory_order_release) cannot cause a race condition with other threads performing the same or other "const" operations (including those mentioned in paragraph 23.2.2.1). However, if another thread invokes a non-const operation on vec itself (e.g. insert, erase, resize etc.) then we experience undefined behaviour as specified by section 1.10:
1.10 Multi-threaded executions and data races [intro.multithread]
...
4 Two expression evaluations conflict if one of them modifies a memory location (1.7) and the other one accesses
or modifies the same memory location.
...
21 The execution of a program contains a data race if it contains two conflicting actions in different threads,
at least one of which is not atomic, and neither happens before the other. Any such data race results in
undefined behavior.
Your expression vec[n].atomic_op(...) is not itself atomic, but decomposes into:
auto iter = vec.begin();
iter += n;
iter->atomic_op(...);
So, the first two statements are vulnerable to the usual iterator invalidation rules. Concurrently changing the size of the vector, or erasing any element before the nth, or the nth element itself, can break them.
Once you have an iterator to an element, if that iterator is not invalidated during the time you're using it, then whatever atomic operations you perform on the element itself will be safe.
Related
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.
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.)
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.
No. Check out PPL or Intel TBB for thread safe STL-like containers.
Like others have noted they have usual "multiple reader thread safety" but that is even pre C++11. Ofc this doesnt mean single writer multiple readers. It means 0 writers. :)
If I've understood correctly, since C++11 it has been safe to call const member functions of a container concurrently and modify the elements of a container as long as the container itself is not modified as part of the operation (as seen from e.g. the table concerning thread safety in cppreference.com). Since std::valarray is not listed in the containers section of the (draft) standard, I'm unsure if thread safety also applies to it. In other words,
Is it safe to read from a std::valarray concurrently (in particular by using operator[] with slices)?
Is it safe to modify the elements of std::valarray<T> concurrently if the operation on T is safe?
I would like to use std::valarray for a multidimensional array of numbers that would be filled using multiple threads.
If I am reading your question correctly, [res.on.data.races] protects distinct slices from participating in data races, under
A C++ standard library function shall not directly or indirectly
access objects accessible by threads other than the current thread
unless the objects are accessed directly or indirectly via the
function's arguments, including this.
[container.requirements.dataraces] adds extra protection around modifications to distinct elements, which strictly valarray lacks.
I am reading about thread safety of various stl containers from this link
Now I came across this point which states for C++11 only
Different elements in the same container can be modified concurrently
by different threads, except for the elements of std::vector<bool>
(for example, a vector of std::future objects can be receiving values
from multiple threads)
Does this mean if I have a method such as this which is being used by multiple
threads simultaneously (notice the method does not have any locks)
void ChangeValue(int index , int value)
{
someVector[index] = value;
}
Is the above method safe. My understanding is that it is safe for C++11 only.
However when I look at the other statement mentioned in the link
All const member functions can be called concurrently by different
threads on the same container. In addition, the member functions
begin(), end(), rbegin(), rend(), front(), back(), data(), find(),
lower_bound(), upper_bound(), equal_range(), at(), and, except in
associative containers, operator[], behave as const for the purposes
of thread safety (that is, they can also be called concurrently by
different threads on the same container). More generally, the C++
standard library functions do not modify objects unless those objects
are accessible, directly or indirectly, via the function's non-const
arguments, including the this pointer.
I come to the conclusion that in C++03 the above method can be safely used as well.
Kindly let me know if my understanding is correct.
It is meaningless to ask whether something is thread-safe under the C++03 standard - C++03 and earlier didn't have any concept of threads or thread safety.
ChangeValue is data race-free (as defined by C++11 and later) as long as no two threads pass the same argument for index, or else calls passing the same argument are synchronized with each other by some means external to the function.
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?
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.
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)
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.
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.)
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.
No. Check out PPL or Intel TBB for thread safe STL-like containers.
Like others have noted they have usual "multiple reader thread safety" but that is even pre C++11. Ofc this doesnt mean single writer multiple readers. It means 0 writers. :)