push_back, begin, end are described as concurrent safe in https://learn.microsoft.com/en-us/cpp/parallel/concrt/reference/concurrent-vector-class?view=vs-2019#push_back
However the below code is asserting. Probably because element is added but not initialized yet.
struct MyData
{
explicit MyData()
{
memset(arr, 0xA5, sizeof arr);
}
std::uint8_t arr[1024];
};
struct MyVec
{
concurrency::concurrent_vector<MyData> v;
};
auto vector_pushback(MyVec &vec) -> void
{
vec.v.push_back(MyData{});
}
auto vector_loop(MyVec &vec) -> void
{
MyData myData;
for (auto it = vec.v.begin(); it != vec.v.end(); ++it)
{
auto res = memcmp(&(it->arr), &(myData.arr), sizeof myData.arr);
assert(res == 0);
}
}
int main()
{
auto vec = MyVec{};
auto th_vec = std::vector<std::thread>{};
for (int i = 0; i < 1000; ++i)
{
th_vec.emplace_back(vector_pushback, std::ref(vec));
th_vec.emplace_back(vector_loop, std::ref(vec));
}
for(auto &th : th_vec)
th.join();
return 0;
}
According to the docs, it should be safe to append to a
concurrency::concurrent_vectorwhile iterating over it because the elements are not actually stored contiguously in memory likestd::vector:However, looking at the actual implementation of
push_backin VS2017, I see the following, which I don't think is thread-safe:I have to speculate on
_Internal_push_backhere, but I'd wager it allocates raw memory for storing the item (and points the last element towards this new node) so that the next line can use emplacement new. I'd imagine that_Internal_push_backis internally thread-safe, however I don't see any synchronization happening before the emplacement new. Meaning the following is possible:memcmpto discover that they're not equalThere's definitely a race condition here. I can spontaneously reproduce the problem, moreso the more threads I use.
I recommend that you open a ticket with Microsoft support on this one.