2016-07-28 12 views
1

Ich habe ein openvdb-Gitter, das ich mit einem Funktor und openvdb :: tools :: foreach iterieren möchte.Wie benutze ich einen openvdb (parallel) für den Zugriff auf mehrere Grids?

//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 { 
    } 
}; 

Wenn der einzigen GI beteiligt Betrieb einfach

Bei jedem Voxel (Iteration), obwohl ich zugreifen müssen und ändern, um zusätzliche Gitter (s) basierend auf dem berechneten Wert der Iteration

Functor op; 
    openvdb::tools::foreach(visibleGrid->cbeginValueOn(), op, true, true); 
genannt haben könnte Schritt.

My inital Lösung beteiligt zum Funktors des zusätzlichen Gitters den Accessor Bereitstellen (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() 
    } 
}; 

die Accessor Functor bei Bauzeit vorgesehen ist, und darüber hinaus jeder Faden der parallel zu einer Kopie erhalten von der Funktor:

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

Leider ist diese Lösung nicht funktionieren, da:

  • die Accessor darf nicht const sein
  • zugegriffen werden
  • aber Functor :: operator() muss eine konstante Methode sein, um von Werkzeugen verwendet werden :: foreach

Eine zweite schmutzig Lösung war, die Functor zu erklären Accessor-Kopie als veränderbar. Diese Lösung funktioniert nicht in Debug aufgrund einer openvdb-Zusicherung fehlgeschlagen (höchstwahrscheinlich ein Speicherverlust).

Gibt es eine Lösung für das Problem? Z.B. a tools :: foreach, das nicht erfordert, dass operator() const ist.

Antwort

1

Es ist nicht sicher, denselben ValueAccessor in verschiedenen Threads zu verwenden. Stattdessen möchten Sie für jeden Thread ValueAccessor s haben, aber teilen Sie den zugrunde liegenden Baum.

Definieren Sie Ihre Functor wie diese statt:

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 
    } 
} 

Der Grund, warum Sie nicht eine nicht-const-Version des Betreibers ist, weil die zugrunde liegende Implementierung beruht auf tbb finden. Die Motivation, die sie in der geben, ist:

Da das Körperobjekt möglicherweise kopiert werden, sollte sein Operator() den Körper nicht ändern. Andernfalls wird die Änderung möglicherweise für den Thread sichtbar, der parallel_for aufgerufen hat, je nachdem, ob operator() auf das Original oder eine Kopie wirkt. Zur Erinnerung an diese Nuance erfordert parallel_for, dass der Operator() des Körperobjekts als const deklariert wird.

Aus diesem Grund sollten Sie in naher Zukunft keine nicht-konstante Version erwarten.

EDIT: Wie in Kommentaren erwähnt, ist es möglich, den Cache in der ValueAccessor wieder zu verwenden. Da es jetzt jedoch ein Mitglied der Klasse ist, werden Sie Probleme haben, den Baum zu modifizieren, indem Sie ihn im Operator verwenden (wie setValue ist nicht-const).Wenn Sie sonst niemand weiß, auf den gleichen Speicherort zu schreiben können Sie einen kleinen Hack tun:

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 
    } 
} 

Ich würde immer noch die erste Lösung bevorzugen. Sie können einen bestimmten Blattknoten zwischenspeichern, indem Sie auf dem Accessor probeLeaf(openvdb::Coord& ijk) aufrufen.

+0

Guter Punkt! Indem ich den Accessor jedes Mal instanziiere, obwohl ich den zuletzt gecachten Baumpfad verliere, auf den zugegriffen wurde. Das gibt mir eine Penaltyperformance – Pierluigi

+0

@Pierluigi Das ist wahr. Was ich auch hinzugefügt haben sollte, ist, dass Sie den Accessor einfach nach Wert anstatt nach Referenz übergeben können, so dass Sie den Cache intakt halten. – pingul

+0

@Pierluigi Ein weiteres Beispiel in der Bearbeitung hinzugefügt. – pingul