I know that is possible to read concurrently from a std::vector
without "bad" consequences because this operation can be considered thread-safe.
But the same cannot be said for writing operations. But, I am wondering if this is not always true, for example considering my particular scenario.
I have a std::vector<bool>
, where all the elements are initialized to false
, and, given an array of indices, I need to change the value of these elements (vector[index]
for each index) from false
to true
.
If I use a different thread for each index (and there is the possibility that some indices have the same value), can this operation be considered thread-safe?
If the vector is a std::vector<int>
(or any primitive type) and the value assigned is always the same (for example 1) can this operation still be considered thread-safe?
The vector<bool> class is a partial specialization of vector for elements of type bool . It has an allocator for the underlying type that's used by the specialization, which provides space optimization by storing one bool value per bit.
Yes, the elements of a std::vector are guaranteed to be contiguous.
Concurrent writes to vector<bool>
are never ok, because the underlying implementation relies on a proxy object of type vector<bool>::reference
which acts as if it was a reference to bool, but in reality will fetch and update the bitfield bytes as needed.
When using multiple threads without synchronization, the following might happen: Thread 1 is supposed to update a bit, and reads the byte containing it. Then thread 2 reads the same byte, then thread 1 updates a bit and writes the byte back, and then thread 2 updates another bit and writes the byte back, overwriting the edit of thread 1.
This is just one possible scenario, there are others that would lead to the same kind of data corruption.
In the vector<int>
situation, if you are absolutely sure that all threads write the same value into the vector, then this operation will generally not lead to data corruption. However, the standard is of course always extra careful and defines all concurrent accesses to a memory location, of which at least one is a write access, to be undefined behavior:
Two expression evaluations conflict if one of them modifies a memory location and the other one reads or modifies the same memory location. – intro.races/2
Therefore, as soon as you do any modification operation on the same element from two different threads, you will have a race condition and need proper synchronization, e.g. by using std::atomic<int>
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With