Wondering if it's safe to iterate over a STL container such as a vector in the following manner to avoid locking on reads/writes but allowing for push_back() operations only by any "writing" threads.
Don't, this is not thread safe. Consider a thread that is trying to read a value and goes to the current buffer. At this time a second thread is growing the buffer, and after the first one obtained the pointer to the buffer, but before it actually read the value, the second thread releases the contents of the buffer. The first thread is reading dead objects, which is undefined behavior.
Restricting the problem to a reserve()
-ed vector (i.e. avoiding the problem of growing the buffer) the approach is still not thread safe. The code in push_back()
will do something similar to:
template <...>
class vector {
T *begin,*end,*capacity; // common implementation uses 3 pointers
void push_back(T value) {
if (end == capacity) { /* grow vector and insert */ }
else {
new (end) T(value);
++end;
}
}
};
The problem here is that without synchronization mechanisms the compiler can reorder the instructions, increment end
and store that to memory, then call the constructor of T
over the buffer element. If that reordering happens, then your reader thread might see a value of size()
that includes the value that is currently being stored, but the value is not yet in the vector.