【问题标题】:Thread-safe read-only alternative to vtkUnstructuredGrid->GetPoint()vtkUnstructuredGrid->GetPoint() 的线程安全只读替代方案
【发布时间】:2019-10-25 08:58:38
【问题描述】:

我已经开始研究多线程和点云处理。问题是我必须在现有实现上实现多线程,并且有太多的读写操作,所以使用互斥锁在性能方面没有给我足够的速度,因为来自grid 的读取操作太多。

最后,我修改了代码,让我可以拥有一个 vtkSmartPointer<vtkUnstructuredGrid>,它包含我的点云。线程必须做的唯一操作是使用GetPoint 方法访问点。但是,由于智能指针,即使您进行只读操作,它也不是线程安全的。

因此,我必须为每个线程复制我的主点云,如果我有太多线程和大云,最后会导致内存问题。

我试图将点云切割成块,但是当我有太多线程时它又变得太复杂了。我不能保证为每个线程处理优化的点数。我也对每个点进行邻居搜索,因此将点云切割成块变得更加复杂,因为我需要为每个块重叠才能获得正确的邻居搜索。

由于vtkUnstructuredGrid是内存优化的,我无法用一些 STL 容器替换它。如果您能向我推荐可用于线程安全读取的点云处理的数据结构,我会很高兴。或者,如果我可以使用任何其他解决方案。

提前致谢

【问题讨论】:

  • 你能解释一下使用互斥锁没有给我足够的速度吗?在性能方面,还是在编码速度方面?
  • @p-a-o-l-o 在性能方面。因为在处理过程中,每个线程从主云读取了很多次(因为许多操作只给出点的 id,然后你必须读取位置),然后它们必须互相等待。例如,当我有 8 个线程时,我的处理速度只能提高一倍。
  • 根据我的经验以及您链接的文档,GetPoint(vtkIdType id, double x[3]) 是线程安全的。你能更详细地解释一下你到底在做什么使它不是线程安全的吗?
  • @tomj 我实际上只是使用GetPoint 从内存中读取。即使它在文档中说线程安全,我也会得到未定义的行为。从 2014 年开始,他们在 vtk 论坛中提到它不是线程安全的,因为 Certainly I can't use vtkSmartPointer, because it accesses a singleton garbage collection mechanism。我不知道该怎么办。
  • 实际上我用GetPoint 阅读,也用vtkSmartPointer<vtkOctreePointLocator> 进行邻域搜索,但他们都不应该修改数据

标签: c++ multithreading performance vtk point-clouds


【解决方案1】:

我不熟悉 VTK 或它的工作原理。

一般来说,有多种技术和方法可以提高多线程环境中的性能。这个问题很模糊,所以我只能提供一个笼统的模糊答案。

  • 简单:如果读取多而写入少,请使用std::shared_mutex,因为它允许同时读取多个。
  • 中等:如果线程大部分时间处理不同的数据:它们访问相同的数据数组但在不同的位置 - 那么您可以实现一个处理程序,确保线程同时处理不同的数据片段没有交集,如果线程要求处理当前正在处理的数据,则告诉它处理其他内容或等待。
  • Hard:有些方法可以通过std::atomic 利用各种内存指令实现高效并发。我不太熟悉它,它绝对不简单,但你可以在互联网上寻找它的教程。据我所知,此类方法的某些部分仍处于研发阶段,尚未开发出最佳实践。

P.S.如果对同一数据有很多读/写...实现是否甚至意识到数据在多个线程上共享这一事实?它甚至可以正确执行吗?您最终可能需要重写整个实现。

【讨论】:

  • 实际上,在我重构代码后,线程没有对同一位置进行任何写操作,但我仍然通过 vtks getPoint() 进行读操作,这不是线程安全的,会导致未定义的行为。关于您的简单实施建议,我每次从点云读取时都使用互斥锁。它似乎不允许同时进行多次读取,因为我没有根据线程数量获得预期的性能改进。你能详细说明一下吗?还是直接给我一个链接?
  • @AliKanat for std::shared_mutex 查看standard C++ reference。您应该使用std::shared_lock<std::shared_mutex> 进行读操作,使用std::unique_lock<std::shared_mutex> 进行写操作。
  • @AliKanat 如果从 lock_guard/unique_lock 切换到 shared_lock 没有提供足够的改进 - 那么瓶颈可能在其他地方。例如,拥有 8 个核心通常意味着您有 4 个核心,每个核心几乎翻倍,但它只能部分作为 2 个核心执行。或者实现使用过多的 RAM 访问 - 全局内存沿所有内核共享,如果您对它有太多的读/写,那么并行化它可能会导致几乎没有改进,具体取决于硬件。多核/多线程主要提高计算速度而不是内存。
  • 我只使用了常规互斥体,我也会尝试使用shared_mutex。感谢您的详细解释。事实上我没有任何写操作。我只有太多的读取操作,但显然由于 vtkSmartPointers 我得到了这个问题。
【解决方案2】:

我只是认为我发布了解决方案,因为它实际上是我的愚蠢。我意识到在我的代码的一部分中我使用了double* vtkDataSet::GetPoint(vtkIdType ptId) 版本的GetPoint(),它不是线程安全的。

对于多线程代码,应使用void vtkDataSet::GetPoint(vtkIdType id,double x[3])

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-13
    • 1970-01-01
    • 2015-07-20
    • 2014-12-12
    • 1970-01-01
    • 1970-01-01
    • 2016-03-15
    相关资源
    最近更新 更多