# GetCellPoints and thread safety

**URL:** https://discourse.vtk.org/t/getcellpoints-and-thread-safety/12809
**Category:** Development
**Created:** [November 29, 2023, 8:21pm UTC](https://discourse.vtk.org/t/getcellpoints-and-thread-safety/12809 "2023-11-29T20:21:52Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![dyollb](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dyollb/32/7649_2.png) [@dyollb](https://discourse.vtk.org/u/dyollb)
#### Post date: [November 29, 2023, 8:21pm UTC](https://discourse.vtk.org/t/getcellpoints-and-thread-safety/12809/1 "2023-11-29T20:21:52Z")

</div>

After upgrading from vtk 8.0 to 9.2.6 several of our tests started becoming flaky.  
It turns out that in some cases (e.g. interpolation) we are calling `GetCellPoints(vtkIdType id, vtkIdType npts, vtkIdType* pts)` of a vtkUnstructuredGrid in different threads (tbb::task\_group, parall\_for, omp, etc).

Reading the docs it seems that we could use the variant that fills a vtkIdList, i.e. `GetCellPoints(vtkIdType id, vtkIdList* ids)`. But the docs say this method is thread-safe IF FIRST CALLED FROM A SINGLE THREAD. I understand that the first call initializes some internal data structure.

- Looking at the code, I cannot see what is being initialized in the first call.
- Also, the API would feel less hacky if we could call e.g. a method `InitializeForThreadSafety()` or similar.

Digging a bit deeper I found this fix:

> <https://github.com/Kitware/VTK/commit/4cd4cc6072181390f7ccf1643348fc6660208860#diff-58970c1bde736caa83df4cbc6a927ce0add05bb02ed9387a17b968b4e6e72864R439>
>
> The method vtkPolyData::GetCellBounds() was no longer thread-safe
> in certain con…ditions (vtkIdType not the same as the underlying
> vtkCellArray storage type).

```cpp
  vtkSmartPointer<vtkCellArrayIterator> iter;
  if (cells->IsStorageShareable())
  {
    // much faster and thread-safe if storage is shareable
    cells->GetCellAtId(tag.GetCellId(), numPts, pts);
  }
  else
  {
    // guaranteed thread safe
    iter = vtk::TakeSmartPointer(cells->NewIterator());
    iter->GetCellAtId(tag.GetCellId(), numPts, pts);
  }

```

Is there a recommended thread safe “nearly” random access API to get the cell points?  
How costly is the vtkCellArrayIterator? In the fix linked above, it says `GetCellAtId` is much faster if the data is sharable.

---

<div class="post-metadata">

### Author: ![dgobbi](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dgobbi/32/18_2.png) [@dgobbi](https://discourse.vtk.org/u/dgobbi)
#### Post date: [November 29, 2023, 9:32pm UTC](https://discourse.vtk.org/t/getcellpoints-and-thread-safety/12809/2 "2023-11-29T21:32:06Z")

</div>

The thread-safety commit that you linked seems to be for `vtkPolyData`, not for `vtkUnstructuredGrid`. Different data classes have different thread-safety concerns, as fiddly as that may seem.

For `vtkUnstructuredGrid`, `GetCellPoints(vtkIdType id, vtkIdList* ids)` is thread safe, as is any variant of the `GetCellPoints()` method that uses a `vtkIdList`.

For `vtkPolyData`, this method is only thread-safe if you call `BuildCells()` first, before starting the multithreading.

As far as I know, there are two “initialization” methods related to thread safety:

1. `BuildCells()` for `GetCellPoints()`
2. `BuildLinks()` for `GetPointCells()`

You’re right that the “if first called from a single thread” condition in the documentation isn’t great, since that isn’t nearly as explicit as having a proper initialization method. And `BuildCells()` could actually be such an initialization method, except that it isn’t part of the `vtkDataSet` API (it’s only for `vtkPolyData`).

A better approach might be to get a `vtkCellArray` from whatever data object you’re working with, and then send that to your threads instead of sending the data object itself.

---

<div class="post-metadata">

### Author: ![dyollb](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dyollb/32/7649_2.png) [@dyollb](https://discourse.vtk.org/u/dyollb)
#### Post date: [November 30, 2023, 7:09am UTC](https://discourse.vtk.org/t/getcellpoints-and-thread-safety/12809/3 "2023-11-30T07:09:01Z")

</div>

Thanks @dgobbi. It seems our second thread safety issue is due to vtkPointSet::ComputeBounds not being thread safe.

We were building a vtkCellLocator in each thread (because in vtk 8.0 vtkCellLocator [was not thread safe](https://github.com/Kitware/VTK/commit/50178e705956cb9bf4a5ae98dfe7e116f820efbd)). vtkCellLocator::BuildLocator calls dataset-\>ComputeBounds(). In our testsuite `vtkCellLocator::FindClosestPoint` sometimes did not find a closest point (`cell_id < 0`). Building a single shared locator before the parallel section fixes the issue.

---

<div class="post-metadata">

### Author: ![spyridon97](https://discourse.vtk.org/user_avatar/discourse.vtk.org/spyridon97/32/7069_2.png) [@spyridon97](https://discourse.vtk.org/u/spyridon97)
#### Post date: [November 30, 2023, 8:23am UTC](https://discourse.vtk.org/t/getcellpoints-and-thread-safety/12809/4 "2023-11-30T08:23:02Z")

</div>

This is the fastest and thread safe GetCellPoints function:

[VTK: vtkUnstructuredGrid Class Reference](https://vtk.org/doc/nightly/html/classvtkUnstructuredGrid.html#af8d425f9863ee3b5eaec51df6b575e0b)

BuildCells is required by vtkPolyData so that the above GetCellPoints is thread safe.

A quick way to initialize a vtkDataSet (including a vtkPolyData) is to perform GetCell(0), which internally calls BuildCells if needed.

Running many multithreaded operations at the same time on the same object is indeed not thread-safe that’s why vtkPointSet::ComputeBounds is not threads safe, but now vtkCellLocator is thread safe, so you are good! Consider using vtkStaticCellLocator for improved built time performance, or vtkCellTreeLocator for better query time but slower built time.
