gpt4 book ai didi

c++ - 如何使用 openvdb(并行)foreach 访问多个网格?

转载 作者:行者123 更新时间:2023-11-30 05:24:33 25 4
gpt4 key购买 nike

我有一个 openvdb 网格,我想使用仿函数和 openvdb::tools::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 {
}
};

如果操作只涉及 G 我可以简单地调用

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

虽然我需要根据迭代步骤的计算值访问和修改额外的网格,但在每个体素(迭代)处。

我最初的解决方案涉及向仿函数提供附加网格的访问器:

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,而且并行的每个线程都获取仿函数的拷贝:

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

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

  • 访问器不能是常量才能被访问
  • 但是 Functor::operator() 必须是 tools::foreach 使用的常量方法

第二个 解决方案是将 Functor 访问器拷贝声明为可变的。由于 openvdb 断言失败(很可能是内存泄漏),此解决方案在调试中不起作用。

这个问题有解决办法吗?例如。不需要 operator() 为常量的 tools::foreach。

最佳答案

在不同线程中使用相同的 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 中给予的动力是:

Because the body object might be copied, its operator() should not modify the body. Otherwise the modification might or might not become visible to the thread that invoked parallel_for, depending upon whether operator() is acting on the original or a copy. As a reminder of this nuance, parallel_for requires that the body object's operator() be declared const.

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

编辑:如评论中所述,可以在 ValueAccessor 中重用缓存。但是,由于它现在是该类的成员,您将无法在运算符中使用它来修改树(因为 setValue 是非常量)。如果你知道没有其他人正在写入同一个内存位置,你可以做一个小 hack:

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) 来缓存某个叶节点。

关于c++ - 如何使用 openvdb(并行)foreach 访问多个网格?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38630373/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com