标准上的 OMP 和并行操作::set<...>::迭代器
OMP and parallel operations on a std::set<...>::iterator
给定基于下图的数据结构:
std::map<int, std::set<std::vector<int>>> cliques;
其中键指示其上包含的向量的大小。
一开始,地图只有一个键(例如[3]
),其中包含输入向量(例如{1, 3, 5}
和{2, 4, 6}
)。
我的函数获取存储在映射最大键中的向量,并将它们分解为具有较少元素的所有可能组合,并将它们存储在与新向量大小相对应的键中(例如[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"和"ompsingle"(而不是"ompfor")可以安全地访问数据结构,同时允许所有其他操作并行运行。代码几乎完美运行,几乎...因为它在最终结果中错过了一些(很少)子向量(如果禁用 OMP 则成功生成)。
是否有任何"OMP专家">可以帮助我解决这个问题?提前谢谢你。
---------------
更新
最小完整可验证示例
我不确定我是否理解您的算法的所有微妙之处,因此我不能完全确定我的分析。免责声明说,我相信会发生以下情况:
您- 没有并行化处理:您不会跨线程分配工作,您只在所有线程上复制相同的工作,这些线程踩在彼此的脚趾上将结果写回同一位置。
- 即使这样做也没有正确完成,因为迭代器的增量(使用
omp single nowait
完成)允许线程在上一次迭代中工作,因为在此阶段不会对it
的值执行同步。(注意:在退出时保护迭代器增量的不带nowait
omp single
具有隐式barrier
,可确保此值的线程一致性视图,因此差异只能在当前迭代和前一个迭代之间) - 这个
cliques[kNew].insert(new_clique);
实际上是所有人都可能爆炸的地方,因为对同一位置的访问是并发的,这是标准容器不支持的。(无论如何,在我的理解范围内,这是错误的)
所以,请再次记住我最初的免责声明,但我认为你的算法本质上是非常错误的,原因有很多,而且它只是偶然地提供了接近你期望的东西。
最后,我正要向你提出我的算法,但由于你的代码片段中缺少很多部分,我就是不能。 如果你发布一个合适的mcve,那么也许我会。
更新根据您的代码,下面是一个可能的并行版本:
for (int k = kMax; k > kMin; k--)
{
std::set<std::vector<int>>::iterator it = cliques[k].begin();
for(int s = 0; s < cliques[k].size(); ++s)
{
std::vector<int> clique = *it;
#pragma omp parallel for num_threads(max_threads)
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);
}
it++;
}
}
相关文章:
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- 呼叫运营商<<临时
- 如何防止clang格式在流运算符调用之间添加换行符<<
- <<操作员在下面的行中工作
- EASTL矢量<向量<int>>连续的
- C - 创建矢量&lt; vector&lt; double&gt;&gt;矩阵具有分配而不是inizializ
- 为什么将此对向量&lt; map&lt; int,int&gt;&gt;中的地图进行更新.失败
- C :对矢量进行排序&lt; struct&gt;(结构有2个整数)基于结构的整数之一
- 明确的专业化“ CheckIntmap&lt;&gt;”实例化
- 什么是模板&lt;&gt;inline bla bla
- 编辑C Qlist&lt; object*&gt; gt;QML代码和一些QML警告中的模型
- eigen :: llt&lt;eigen :: matrixxd&gt;具有不完整的类型
- 错误,包括&lt; ctype&gt;在原子上使用C 11
- std::vector<;uint8_t>;当C++11/14启用时,手动复制而不是调用memcpy
- 如何加入向量&lt; int&gt;到C 中的单个INT
- 是std :: set&lt; std :: future&gt;不可能存在
- 是numeric_limits&lt; int&gt; :: is_modulo从逻辑上矛盾
- opencv 2.4.7在iOS错误背景_segm.hpp #include&lt; list&gt;未找到
- 在修改列表后,std :: list&lt; t&gt; :: end()的值是否会更改
- ///<评论></评论>在Visual Studio中