【发布时间】:2018-04-09 21:46:10
【问题描述】:
给定一个基于 map 的数据结构,如下所示:
std::map<int, std::set<std::vector<int>>> cliques;
键表示其中包含的向量的大小。
一开始,map只有一个键(例如[3]),其中包含输入向量(例如{1, 3, 5}和{2, 4, 6})。
我的函数把map的biggest key中存储的vectors分解成所有的可能具有较少元素的组合,并将它们存储在与新向量的大小相对应的键中(例如[2] = {1,3} {1,5} {3,5} {2,4} {2,6} {4,6} and [1] = {1} {3} {5} {2} {4} {6})。
我不知道我的解决方案是否最有效,但效果很好。但由于我的项目旨在处理大量数据,我需要并行化我的代码,这导致我进行了以下实现:
/// Declare data structure
std::map<int, std::set<std::vector<int>>> cliques;
/// insert "input" vectors
cliques[5] = {{1, 3, 5, 7, 9}};
cliques[4] = {{1, 2, 3, 4}};
/// set boundaries
int kMax = 5;
int kMin = 1;
/// enable/disable parallel execution
bool parallelExec = true;
/// "decompose" source vectors:
for (int k = kMax; k > kMin; k--)
{
std::set<std::vector<int>>::iterator it = cliques[k].begin();
#pragma omp parallel num_threads(max_threads) if(parallelExec)
{
for(int s = 0; s < cliques[k].size(); ++s)
{
std::vector<int> clique;
/// maybe should be "omp critical"?
/// maybe "clique" should be private? (or is it already??)
#pragma omp single
{
clique = *it;
}
for (int v = 0; v < clique.size(); ++v)
{
int& vertex = clique[v];
std::vector<int> new_clique;
std::copy_if(clique.begin(), clique.end(), std::back_inserter(new_clique), [vertex](const int& elem) { return elem != vertex; });
int kNew = k - 1;
#pragma omp critical
{
cliques[kNew].insert(new_clique);
}
}
#pragma omp single
{
it++;
}
}
}
}
/// Display results
for(int i = cliques.size(); i > 0 ; i--)
{
auto kSet = cliques[i];
std::cout << "[" << i << "]: ";
for(auto& vec : kSet)
{
std::cout << "{";
for(auto& elem : vec)
{
std::cout << elem << " ";
}
std::cout << "} ";
}
std::cout << std::endl;
}
使用 “omp parallel” 和 “omp single”(而不是“omp for”)允许安全地访问数据结构,同时允许所有其他操作并行运行。该代码几乎完美地工作,几乎......因为它在最终结果中遗漏了一些(非常少的)子向量(如果禁用 omp,则会成功生成这些子向量)。
有没有“OMP 专家”可以帮助我解决这个问题?提前谢谢你。
---------------
更新
【问题讨论】:
-
标准库容器不支持并发访问,尤其是
std::set。查找支持并行访问的 C++ 容器库 - 或创建单独的集合,然后合并它们。 -
@einpoklum stl 容器(向量和队列除外)不支持并发访问,但我阅读了一些示例,其中可以在“omp 并行”区域内使用“omp single”完成(顺序)访问而不是“omp for”同时执行所有其他操作,这就是我尝试的全部内容。
标签: c++ openmp stdmap clique-problem