在std :: set< ...> :: iterator上的OMP和并行操作

时间:2018-04-09 21:46:10

标签: c++ openmp stdmap clique-problem

根据下面显示的地图给出数据结构:

std::map<int, std::set<std::vector<int>>> cliques;

表示其中包含的向量的大小

一开始,地图只有一个(例如[3]),其中包含输入向量(例如{ {1}}和{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}

使用“omp parallel”“omp single”(而不是“omp for”)可以安全地访问数据结构,同时允许所有其他操作并行运行。代码工作几乎完美,差不多......因为它在最终结果中遗漏了一些(很少的)子向量(如果禁用omp则成功生成)。

有没有“OMP专家”能够帮我解决这个问题?提前谢谢。

---------------

更新

Minimal Complete Verifiable Example

1 个答案:

答案 0 :(得分:2)

我不确定我理解算法的所有微妙之处,因此我不能完全确定我的分析。免责声明说,这就是我认为发生的事情:

  1. 您没有并行化处理:您不会跨线程分发工作,您只需在所有线程上复制相同的工作,这些工作会相互踩踏,将结果写回到相同的线程中位置。
  2. 即使没有正确完成,因为迭代器的增量(使用omp single nowait完成)允许线程在前一次迭代中工作,因为it的值没有同步在这个阶段进行。 (注意:退出时保护迭代器增量的omp single没有nowait有一个隐式barrier,它确保了该值的线程连贯视图,因此差异只能在当前迭代和前一个迭代)
  3. 这个cliques[kNew].insert(new_clique);实际上是所有可以爆炸的地方,因为对同一位置的访问是并发的,标准容器不支持。 (无论如何,这是错误的,达到我理解的极限)
  4. 再说一次,请记住我最初的免责声明,但我认为你的算法本质上是非常错误的,原因有很多,并且它只是偶然地提供了一些接近你期望的东西。

    最后,我打算向你提出一个我的算法,但由于你的代码片段中缺少很多部分,我只能这样做。 如果您发布了正确的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++;
        }
    }
    
相关问题