pid*_*gun 9 c++ concurrency concurrent-vector
push_back, begin, end are described as concurrent safe in https://docs.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;
}
Run Code Online (Sandbox Code Playgroud)
根据文档,在迭代它时追加到 a while 应该是安全的,concurrency::concurrent_vector因为元素实际上并不是连续存储在内存中,例如std::vector:
当您追加到对象或调整其大小时,对象
concurrent_vector不会重新定位其元素。这使得现有的指针和迭代器在并发操作期间保持有效。
但是,查看push_backVS2017 中的实际实现,我看到以下内容,我认为这不是线程安全的:
iterator push_back( _Ty &&_Item )
{
size_type _K;
void *_Ptr = _Internal_push_back(sizeof(_Ty), _K);
new (_Ptr) _Ty( std::move(_Item));
return iterator(*this, _K, _Ptr);
}
Run Code Online (Sandbox Code Playgroud)
我必须在_Internal_push_back这里推测,但我敢打赌它会分配原始内存来存储该项目(并将最后一个元素指向这个新节点),以便下一行可以使用新的位置。我想这_Internal_push_back是内部线程安全的,但是我没有看到在安置新之前发生任何同步。意味着以下情况是可能的:
memcmp发现它们不相等这里肯定存在竞争条件。我可以自发地重现该问题,而且我使用的线程越多。
我建议您向 Microsoft 支持开具一张票证。
| 归档时间: |
|
| 查看次数: |
113 次 |
| 最近记录: |