Using multiple threads with IVtk_IShapeMesher::Build() corrupts `theData` structure *on Windows*

After many tests I have come to conclusion that IVtk_IShapeMesher::Build() must be corrupting data structure when run with multiple threads.
I have run tests with OMP (#pragma omp parallel for) and std::thread.

What we have is a loop in which threads are created and function is being run.

The meta - code of function is like this:

function(<args,shape;args>)
{
IVtkOCC_Shape::Handle aShapeImpl = new IVtkOCC_Shape(shape);
if (!aShapeImpl.IsNull())
{
IVtkVTK_ShapeData::Handle aDataImpl = new IVtkVTK_ShapeData();
IVtk_IShapeMesher::Handle aMesher = new IVtkOCC_ShapeMesher(<some_args>);

//this is where we crash when run with multiple threads - `Access Violation`;
//if we run it with '#pragma omp critical' for OMP, which will execute block of code in a single thread at a time - no exceptions are thrown.
aMesher->Build(aShapeImpl, aDataImpl);

//... some more code

}

}

Any comments or ideas on how to get this running in multiple threads are welcome.
Change the approach maybe ?

Kirill Gavrilov's picture

IVtkOCC_ShapeMesher internally calls BRepTools::Clean() and BRepMesh_IncrementalMesh. These tools work with the triangulation cache stored directly within TopoDS_Shape structures.

Therefore, if shapes passed as an input to your "function(<args,shape;args>)" share common sub-shapes, then calling IVtkOCC_ShapeMesher within concurrent threads may lead to data races on modifications of TopoDS_Shape tessellation cache.

There are several approaches to avoid data races within tessellation cache:

  • Disallow implicit auto-triangulation and create triangulation explicitly in advance.
    Within OCCT 7.6.0 development branch, this can be managed via Prs3d_Drawer::IsAutoTriangulation() property of a draw passed to IVtkOCC_Shape.
    Within older OCCT versions, hack will be necessary.
    Calling BRepMesh_IncrementalMesh on the whole shape would also allow using multi-threading optimizations of this algorithm.
     
  • Make a (deep) copy of TopoDS_Shape before passing it to specific thread within the multi-threaded algorithm.
    This could be done with help of BRepBuilderAPI_Copy.
    Note that duplicated TopoDS_Shape will return FALSE when compared to original shapes.
Haralds Kaulins's picture

Thank You for such a quick response.
I will look into this and report.