Thread-safety of writing a std::vector vs plain array

clstaudt picture clstaudt · Dec 19, 2012 · Viewed 10.2k times · Source

I've read on Stackoverflow that none of the STL containers are thread-safe for writing. But what does that mean in practice? Does it mean I should store writable data in plain arrays?

I expect concurrent calls to std::vector::push_back(element) could lead to inconsistent data structures becaue it might entail resizing the vector. But what about a case like this, where resizing is not involved:

1) using an array:

int data[n];
// initialize values here...

#pragma omp parallel for
for (int i = 0; i < n; ++i) {
    data[i] += func(i);
}

2) using a `std::vector``:

std::vector<int> data;
data.resize(n);
// initialize values here...

#pragma omp parallel for
for (int i = 0; i < n; ++i) {
    data[i] += func(i);
}

Is the first implementation really better than the second one a) in terms of thread-safety and b) in terms of performance? I would prefer to use a std::vector, since I am less comfortable with C-style arrays.

EDIT: I removed a #pragma omp atomic update protecting the write.

Answer

Steve Jessop picture Steve Jessop · Dec 19, 2012

The two are equally safe. Provided no element is accessed from multiple threads you're OK. Your parallel loop will access each element only once, and hence only from one thread.

There's space in the standard for the member functions of containers to be non-thread-safe. In this case you use vector<int>::operator[], so you'd want an explicit guarantee of thread-safety for that member, which seems reasonable since calling it even on a non-const vector doesn't modify the vector itself. So I doubt that there's a problem in this case, but I haven't looked for the guarantee [edit: rici found it]. Even if it's potentially unsafe, you could do int *dataptr = &data.front() before the loop and then index off dataptr instead of data.

As an aside, this code is not guaranteed safe for vector<bool>, since it's a special-case for which multiple elements co-exist inside one object. It would be safe for an array of bool, since the different elements of that are different "memory locations" (1.7 in C++11).