我有一个使用很多std::map
结构的程序。现在,我想将它们与多个线程一起使用,并假定插入或删除键可能会更改整个数据结构并并行破坏它。但是,当我不添加新 key 时,应该没问题吧?
以下程序显示了我想做什么:
#include <omp.h>
#include <iostream>
#include <map>
int main(int const argc, char const *const *const argv) {
// Take a map and allocate the elements, but not fill them at this point.
std::map<int, int> map;
int size = 10000;
for (int i = 0; i < size; ++i) {
map[i];
}
// Go through the elements in parallel and write to them, but not create any
// new elements. Therefore there should not be any allocations and it should
// be thread-safe.
#pragma omp parallel
{
int const me = omp_get_thread_num();
#pragma omp for
for (int i = 0; i < size; ++i) {
map[i] = me;
}
}
// Now all threads access all the elements of the map, but as the map is not
// changed any more, nothing bad should happen.
#pragma omp parallel
{
int const me = omp_get_thread_num();
int self = 0;
for (int i = 0; i < size; ++i) {
if (map[i] == me) {
++self;
}
}
#pragma omp critical(cout)
std::cout << "Thread " << me << " found " << self << " entries.\n";
}
}
然后用以下代码进行编译:
$ g++ -fopenmp -O3 -Wall -Wpedantic -g -fsanitize=address -o concurrent-map concurrent-map.cpp
这似乎与四个线程一起正常工作。如果我注释掉第一个for循环并让线程填充映射,则它会由于我期望的段错误而崩溃。
当然,我不能以这种方式证明
std::map
是线程安全的,但至少不能证明它是负面的。我可以并行使用std::map
吗? 最佳答案
我认为使用map[i]
并不是对所有C++实现都是线程安全的,即使它没有插入新元素也是如此。该标准不要求operator[]
不受关联容器的数据竞争的影响:
C++ 17标准草案的[container.requirement.dataraces]/1节包含一个不引起数据争用的函数列表,即使它们不是const
。该列表包括find
和at
,但不包括operator[]
。
因此,您需要使用find
或at
而不是operator[]
。特定的实现可能会提供更强的保证,并且如果map[i]
没有插入新元素,则可能会实现,但是您需要与编译器/标准库文档一起检查这一点。
除此之外,访问,甚至修改容器的其他元素总是可以的(vector<bool>
除外),请参阅标准的下一段。
关于c++ - 当我不添加/删除键时,可以并行使用std::map吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58692995/