使用并行线程填充集合有啥危险吗?
Posted
技术标签:
【中文标题】使用并行线程填充集合有啥危险吗?【英文标题】:Is there any danger in populating a set using parallel threads?使用并行线程填充集合有什么危险吗? 【发布时间】:2017-11-29 01:00:36 【问题描述】:我可以使用 C++ 中的并行线程填充 std::set
对象并编辑布尔向量吗?
我对并行计算比较陌生,刚刚学习使用 OpenMP,我听说有人说线程之间可以共享数据结构,只要它们是只读的。
我的问题是,我可以使用并行方法填充一些数据结构,只要顺序无关紧要吗?还是您通常不做类似事情的原因不仅仅是订单不会被保留?
这是我想要做的:
input: std::vector<Object> u_set // vector containing universal set
int NUM_ELEMENTS = 1000;
std::set<int> my_set(); // set to be populated
std::vector<bool> my_bools(u_set.size(), false); // vector containing set membership information (true/false)
#pragma omp parallel for
for (int i = 0; i < NUM_ELEMENTS; ++i)
int next_el = get_next_element(); // next element from u_set
my_set.insert(next_el);
my_bools[next_el] = true;
代码基本上从通用集中选择一个元素,然后将其值添加到子集中,并将其标记在布尔向量中作为子集的成员。可以并行执行此操作吗?还是被认为是不好的形式?这样的东西会更好吗?
input: std::vector<Object> u_set // vector containing universal set
int NUM_ELEMENTS = 1000;
std::set<int> my_set(); // set to be populated
std::vector<bool> my_bools(u_set.size(), false); // vector containing set membership information (true/false)
int max_threads = omp_get_max_threads();
std::vector<std::vector<int> > elements(max_threads); // vector to contain data from each thread, so not accessing the same data structure
#pragma omp parallel for
for (int i = 0; i < NUM_ELEMENTS; ++i)
int next_el = get_next_element(); // next element from u_set
int curr_thread = omp_get_thread_num();
elements[curr_thread].push_back(next_el);
for (auto it = elements.begin(); it != elements.end(); ++it)
for (auto jt = elements[*it].begin(); jt != elements[*it].end(); ++it)
my_set.insert(*jt);
my_bools[*jt] = true;
这会为每个线程创建一个单独的向量,然后在最后将它们组合起来。我知道它在技术上仍然在访问相同的数据结构,但在我看来,将向量在整个数据结构中分开会使其免受混淆的额外安全级别。
这是更好的方法吗?还是只访问同一个集合并随着算法的进行添加就可以了?
【问题讨论】:
简短的回答是:不。std::set
不是线程安全的。
只有const
成员函数可以被并发访问。见en.cppreference.com/w/cpp/container#Thread_safety
很公平,您有什么建议可以并行化此代码吗?第二种方式安全吗?因为它没有在相同的向量上调用 push_back?
【参考方案1】:
当任何其他线程调用任何其他方法时,您不能调用std
容器的几乎所有非const
方法。 (begin()
和 end()
和其他一些是例外)。
所以没有。
其他并行库中使用的一种技术是,每个线程将更改累积在一个子容器中,工作线程以类似二叉树的方式自动将其合并到最终结果中。对于您使用的工具,这似乎不太合理。
【讨论】:
那么即使是第二种方式也行不通?为每个线程保留一个单独的向量?以上是关于使用并行线程填充集合有啥危险吗?的主要内容,如果未能解决你的问题,请参考以下文章