2016-07-28 51 views
1

我有一个openvdb网格,我想迭代使用函子和openvdb :: tools :: foreach。如何使用openvdb(并行)的foreach访问多个网格?

//the grid I am iterating on 
Grid G; 

//the operator used to update each single voxel of G 
struct Functor{ 
    inline void operator()(const Grid::ValueOnCIter& iter) const { 
    } 
}; 

如果只涉及胃肠道的操作可以基于迭代的计算值都简称

Functor op; 
    openvdb::tools::foreach(visibleGrid->cbeginValueOn(), op, true, true); 

在每个体素(迭代),虽然我需要访问和修改其他电网(S)步。

我inital解决方案涉及提供给仿函数的附加电网(S)的访问:

struct Functor{ 
    Grid2::Accessor grid2_accessor; 

    Functor(Grid2::Accessor& a) : grid2_accessor(a){} 

    inline void operator()(const Grid::ValueOnCIter& iter) const { 
     //use grid2_accessor based on iter.getCoord() 
    } 
}; 

存取提供给函子,在施工时间,而且每个并行的线程得到的副本仿函数:

Functor op(G2->getAccessor()); 
    openvdb::tools::foreach(G1->cbeginValueOn(), op, true, **false**); 

不幸的是这种解决方案不起作用,因为:

  • 存取器必须不能被访问
  • 常量但函子::运算符()必须是一个const方法通过工具一起使用的foreach ::

第二溶液申报函子访问器复制为可变。由于openvdb断言失败(很可能是内存泄漏),此解决方案在Debug中不起作用。

有问题的解决方案吗?例如。一个工具:: foreach不要求operator()是const。

回答

1

在不同的线程中使用相同的ValueAccessor是不安全的。相反,您希望每个线程都有独特的ValueAccessor,但共享底层树。

定义您Functor这样,而不是:

struct Functor { 
    Grid2& mGrid2; 
    Functor(Grid2& grid2) : mGrid2(grid2) {} 

    void operator()(const Grid::ValueOnCIter& iter) const { 
     Grid2::Accessor grid2Acc(grid2.getAccessor()); // This is allowed because Grid2 is a reference 
     // Do what you want 
    } 
} 

你找不到运营商的非const版本的原因是因为底层的实现依赖于tbb。他们在tbb documentation中给出的动机是:

因为可以复制正文对象,所以它的operator()不应修改正文。否则,修改可能会或可能不会对调用parallel_for的线程可见,具体取决于operator()是在原始还是副本上进行操作。作为这种细微差别的提醒,parallel_for要求body对象的operator()被声明为const。

正因为如此,您不应该期待很快就会有一个非const版本。

编辑:正如评论中指出的那样,可以重新使用ValueAccessor中的缓存。但是,因为它现在是类的成员,所以在操作符中使用它修改树会有问题(因为setValue是非const)。如果你知道没有其他人被写入同一存储空间,你可以做一个小的黑客:

struct Functor { 
    Grid2::ValueAccessor mGrid2Acc; 
    Functor(Grid2::ValueAccessor grid2Acc) : mGrid2Acc(grid2Acc) {} 

    void operator()(const Grid::ValueOnCIter& iter) const { 
     const Grid2::ValueType& v = mGrid2Acc.getValue(iter.getCoord()); 
     Grid2::ValueType& non_const_v = const_cast<Grid2::ValueType&>(v); 
     // modify the value as you please, however a race condition will occur 
     // if more than 1 thread write to the same location 
    } 
} 

我仍倾向于第一方案。您可以通过在访问器上调用probeLeaf(openvdb::Coord& ijk)来缓存某个叶节点。

+0

好点!通过每次实例化访问器,尽管我失去了上一次访问的缓存树路径。这给了我一个表演处罚 – Pierluigi

+0

@Pierluigi这是真的。我应该添加的是,您可以通过值而不是通过引用传递访问器,这样可以保持缓存完好无损。 – pingul

+0

@Pierluigi在编辑中添加了另一个示例。 – pingul

相关问题