【问题标题】:Why does OpenMP not parallelize vtk IntersectWithLine code为什么 OpenMP 不并行化 vtk IntersectWithLine 代码
【发布时间】:2017-08-09 11:36:58
【问题描述】:

如果在循环内执行 Vtk 代码,我很难理解为什么与 OpenMP 并行的 for-loop 不会使用所有 n_threads 线程 (=2x #cores)。具体来说,我想将线/射线与网格相交。我关注了this tutorial

  1. 从网格构建 OBB 树
  2. 将所有需要的线与网格相交

因为我想并行化它,所以我创建了n_threads 树,这样每个线程都可以使用它自己的树实例:

// Pre-allocate the array
int n_threads = omp_get_max_threads();
trees = std::vector<vtkSmartPointer<vtkOBBTree>>((unsigned int) n_threads);

// Build n_threads OBB trees
#pragma omp parallel for num_threads(n_threads)
for (int t = 0; t < n_threads; ++t)
{
    trees[t] = vtkSmartPointer<vtkOBBTree>::New();
    vtkSmartPointer<vtkPolyData> mesh_clone = vtkSmartPointer<vtkPolyData>::New();
    #pragma omp critical (build_mesh_tree)
    {
        mesh_clone->DeepCopy(mesh);
    }
    trees[t]->SetDataSet(mesh_clone);
    trees[t]->BuildLocator();
}

然后我遍历所有点来计算originpoints中每个点的交集

#pragma omp parallel for num_threads(n_threads)
for (unsigned long i = 0; i < n_points; ++i)
{
    vtkSmartPointer<vtkPoints> intersection_points = vtkSmartPointer<vtkPoints>::New();
    vtkSmartPointer<vtkIdList> cell_ids = vtkSmartPointer<vtkIdList>::New();

    int this_thread = omp_get_thread_num();
    int code = trees[this_thread]->IntersectWithLine(
            origin.data(),       // pointer to the raw data
            points.at(i).data(), // buffer of a Eigen matrix
            intersection_points,
            cell_ids);

    // Do something with intersection_points and cell_ids
}

OpenMP 对于简单的 C++ 代码已经证明可以正常工作。然而,当包裹 Vtk 调用时,它并没有达到它的目的。我想这是因为 Vtk 已经提供了parallelization framework (ref. to the guide)。

如果是这样,您能否解释一下,为什么 OpenMP 无法并行运行与 vtk 相关的代码?如果不是,可能是什么原因?

【问题讨论】:

    标签: c++ multithreading parallel-processing openmp vtk


    【解决方案1】:

    它究竟是如何失败的?你试过吗?打印线程号以查看是否生成了 n_threads?如果您“只是”在intersection_pointscell_ids 中得到错误结果,那是因为这些数组在每个线程进入IntersectWithLine 函数时都会被重置(您可以查看实现here,第800 行-808)。

    为了解决这个问题,想到的最简单的解决方案是让每个线程都有自己的列表,然后在关键部分将它们连接起来,但更快的方法可能是为每个线程预先分配这些列表的数组,然后读取结果,例如:

    vtkSmartPointer<vtkPoints> *inter_points = new vtkSmartPointer<vtkPoints> [n_threads];
    vtkSmartPointer<vtkIdList> *inter_cells = new vtkSmartPointer<vtkIdList> [n_threads];
    for (unsigned long i = 0; i < n_threads; ++i)
    {
        inter_points[i] = vtkSmartPointer<vtkPoints>::New();
        inter_cells[i] = vtkSmartPointer<vtkIdList>::New();
    }
    
    #pragma omp parallel for num_threads(n_threads)
    for (unsigned long i = 0; i < n_points; ++i)
    {
        int this_thread = omp_get_thread_num();
        int code = trees[this_thread]->IntersectWithLine(
                origin.data(), // pointer to the raw data
                points.at(i).data(), // buffer of a Eigen matrix
                inter_points[this_thread],
                inter_cells[this_thread);
    }
    
    // now concatenate the results to one array if necessarry
    

    (没有编译,可能有语法错误,只是普通的 C,所以不是最安全的方法...)

    【讨论】:

    • 感谢您的回复!我在上面更新了我的问题。当然,覆盖intersection_pointsintersection_cells 的内容(可能线程不安全)是没有意义的。我现在将这段代码移到循环中。我也不清楚 OpenMP 如何失败。计算是正确的。它只是不会同时在所有线程上执行代码的 vtk 部分。我可以确认n_threads 已生成。似乎首先调用 vtk 函数的线程锁定了其他线程。
    猜你喜欢
    • 2021-08-10
    • 1970-01-01
    • 1970-01-01
    • 2021-10-18
    • 1970-01-01
    • 2017-09-12
    • 2012-07-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多