`LabelVector::IsLabelValue` is not thread-safe but `vtkDiscreteClipperAlgorithm<T>::ClassifyXEdges` expects it to be
vtkDiscreteClipperAlgorithm<T>::ClassifyXEdges
is documented to be expected to be run from multiple threads:
// The three threaded passes of the algorithm.
void ClassifyXEdges(T* inPtr, vtkIdType row); // PASS 1
void ClassifyYEdges(T* inPtr, vtkIdType row); // PASS 2
void GenerateOutput(T* inPtr, vtkIdType row); // PASS 4
but one of the first things it does is:
bool isCVx = this->LMap->IsLabelValue(sx);
Problem is, LabelVector::IsLabelValue
is not thread safe, its getters sometimes mutate its internal state:
bool IsLabelValue(T label) override
{
bool inLabelSet;
// Check the cache
if (this->IsLabelValueInCache(label, inLabelSet)) // 🔥🔥🔥 reads both CachedOutValue and CachedOutValueInitialized
{
return inLabelSet;
}
// Not in the cache, check the vector
if (std::find(this->Map.begin(), this->Map.end(), label) != this->Map.end())
{
this->CachedValue = label;
return true;
}
else
{
this->CachedOutValue = label; // 🔥🔥🔥 a write here
this->CachedOutValueInitialized = true; // 🔥🔥🔥 a write here
return false;
}
}
Maybe it would be sufficient to make these ivars std::atomic
... CachedOutValueInitialized
is always set after CachedOutValue
and always checked before, so might be sufficiently safe...