Skip to content

Commit b66133a

Browse files
seanmdzenanz
authored andcommitted
BUG: fixed thread safety errors found by Thread Sanitizer
std::vector<bool> has less thread safety than vectors of other types, because multiple boolean bits can be packed into the same byte(s). C++11 standard § 23.2.2, paragraph 2 describes this futher. So instead, just use uint8_t instead of bool. This allows enough thread safety for the usage at hand, as evidenced by various tests now passing under thread sanitizer.
1 parent b2c2c34 commit b66133a

12 files changed

+29
-18
lines changed

Modules/Core/FiniteDifference/include/itkDenseFiniteDifferenceImageFilter.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,10 @@ class ITK_TEMPLATE_EXPORT DenseFiniteDifferenceImageFilter
172172
DenseFiniteDifferenceImageFilter * Filter;
173173
TimeStepType TimeStep;
174174
std::vector<TimeStepType> TimeStepList;
175-
std::vector<bool> ValidTimeStepList;
175+
176+
// NB: although semantically boolean, vector<bool> is not thread safe due to the possibility of multiple bits being
177+
// packed together in the same memory location.
178+
std::vector<uint8_t> ValidTimeStepList;
176179
};
177180

178181
/** This callback method uses ImageSource::SplitRequestedRegion to acquire an

Modules/Core/FiniteDifference/include/itkFiniteDifferenceImageFilter.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -330,12 +330,12 @@ class ITK_TEMPLATE_EXPORT FiniteDifferenceImageFilter : public InPlaceImageFilte
330330
*
331331
* \param timeStepList The set of time changes compiled from all the threaded calls
332332
* to ThreadedGenerateData.
333-
* \param valid The set of flags indicating which of "list" elements are
334-
* valid
333+
* \param valid The set of flags indicating which of "timeStepList" elements are
334+
* valid. Although they are uint8_t, they should be treated like bools.
335335
*
336336
* The default is to return the minimum value in the list. */
337337
virtual TimeStepType
338-
ResolveTimeStep(const std::vector<TimeStepType> & timeStepList, const std::vector<bool> & valid) const;
338+
ResolveTimeStep(const std::vector<TimeStepType> & timeStepList, const std::vector<uint8_t> & valid) const;
339339

340340
/** Set the number of elapsed iterations of the filter. */
341341
itkSetMacro(ElapsedIterations, IdentifierType);

Modules/Core/FiniteDifference/include/itkFiniteDifferenceImageFilter.hxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ FiniteDifferenceImageFilter<TInputImage, TOutputImage>::GenerateInputRequestedRe
167167
template <typename TInputImage, typename TOutputImage>
168168
typename FiniteDifferenceImageFilter<TInputImage, TOutputImage>::TimeStepType
169169
FiniteDifferenceImageFilter<TInputImage, TOutputImage>::ResolveTimeStep(const std::vector<TimeStepType> & timeStepList,
170-
const std::vector<bool> & valid) const
170+
const std::vector<uint8_t> & valid) const
171171
{
172172
TimeStepType oMin = NumericTraits<TimeStepType>::ZeroValue();
173173
bool flag = false;

Modules/Core/FiniteDifference/include/itkFiniteDifferenceSparseImageFilter.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,10 @@ class ITK_TEMPLATE_EXPORT FiniteDifferenceSparseImageFilter
197197
FiniteDifferenceSparseImageFilter * Filter;
198198
TimeStepType TimeStep;
199199
std::vector<TimeStepType> TimeStepList;
200-
std::vector<bool> ValidTimeStepList;
200+
201+
// NB: although semantically boolean, vector<bool> is not thread safe due to the possibility of multiple bits being
202+
// packed together in the same memory location.
203+
std::vector<uint8_t> ValidTimeStepList;
201204
};
202205

203206
private:

Modules/Core/FiniteDifference/include/itkFiniteDifferenceSparseImageFilter.hxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ FiniteDifferenceSparseImageFilter<TInputImageType, TSparseOutputImageType>::Calc
167167
// Initialize the list of time step values that will be generated by the
168168
// various threads. There is one distinct slot for each possible thread,
169169
// so this data structure is thread-safe. All of the time steps calculated
170-
// in each thread will be combined in the ResolveTimeStepMethod.
170+
// in each thread will be combined in the ResolveTimeStep method.
171171
ThreadIdType workUnitCount = this->GetMultiThreader()->GetNumberOfWorkUnits();
172172

173173
str.TimeStepList.resize(workUnitCount, false);

Modules/Core/GPUFiniteDifference/include/itkGPUFiniteDifferenceImageFilter.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,12 +240,12 @@ class ITK_TEMPLATE_EXPORT GPUFiniteDifferenceImageFilter
240240
*
241241
* \param timeStepList The set of time changes compiled from all the threaded calls
242242
* to ThreadedGenerateData.
243-
* \param valid The set of flags indicating which of "list" elements are
244-
* valid
243+
* \param valid The set of flags indicating which of "timeStepList" elements are
244+
* valid. Although they are uint8_t, they should be treated like bools.
245245
*
246246
* The default is to return the minimum value in the list. */
247247
TimeStepType
248-
ResolveTimeStep(const std::vector<TimeStepType> & timeStepList, const std::vector<bool> & valid) const override;
248+
ResolveTimeStep(const std::vector<TimeStepType> & timeStepList, const std::vector<uint8_t> & valid) const override;
249249

250250
/** This method is called after the solution has been generated to allow
251251
* subclasses to apply some further processing to the output. */

Modules/Core/GPUFiniteDifference/include/itkGPUFiniteDifferenceImageFilter.hxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ template <typename TInputImage, typename TOutputImage, typename TParentImageFilt
183183
typename GPUFiniteDifferenceImageFilter<TInputImage, TOutputImage, TParentImageFilter>::TimeStepType
184184
GPUFiniteDifferenceImageFilter<TInputImage, TOutputImage, TParentImageFilter>::ResolveTimeStep(
185185
const std::vector<TimeStepType> & timeStepList,
186-
const std::vector<bool> & valid) const
186+
const std::vector<uint8_t> & valid) const
187187
{
188188
TimeStepType oMin = NumericTraits<TimeStepType>::ZeroValue();
189189
bool flag = false;

Modules/Nonunit/Review/include/itkMultiphaseFiniteDifferenceImageFilter.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,11 +515,12 @@ class ITK_TEMPLATE_EXPORT MultiphaseFiniteDifferenceImageFilter : public InPlace
515515
* \param timeStepList The set of time changes compiled from all the threaded
516516
* calls to ThreadedGenerateData.
517517
*
518-
* \param valid The set of flags indicating which of "list" elements are valid
518+
* \param valid The set of flags indicating which of "timeStepList" elements are
519+
* valid. Although they are uint8_t, they should be treated like bools.
519520
*
520521
* The default is to return the minimum value in the list. */
521522
inline TimeStepType
522-
ResolveTimeStep(const TimeStepVectorType & timeStepList, const std::vector<bool> & valid);
523+
ResolveTimeStep(const TimeStepVectorType & timeStepList, const std::vector<uint8_t> & valid);
523524

524525
/** This method is called after the solution has been generated to allow
525526
* subclasses to apply some further processing to the output. */

Modules/Nonunit/Review/include/itkMultiphaseFiniteDifferenceImageFilter.hxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ typename MultiphaseFiniteDifferenceImageFilter<TInputImage,
201201
TFiniteDifferenceFunction,
202202
TIdCell>::TimeStepType
203203
MultiphaseFiniteDifferenceImageFilter<TInputImage, TFeatureImage, TOutputImage, TFiniteDifferenceFunction, TIdCell>::
204-
ResolveTimeStep(const TimeStepVectorType & timeStepList, const std::vector<bool> & valid)
204+
ResolveTimeStep(const TimeStepVectorType & timeStepList, const std::vector<uint8_t> & valid)
205205
{
206206
TimeStepType oMin = NumericTraits<TimeStepType>::ZeroValue();
207207
const SizeValueType size = timeStepList.size();

Modules/Numerics/NarrowBand/include/itkNarrowBandImageFilterBase.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,9 @@ class ITK_TEMPLATE_EXPORT NarrowBandImageFilterBase : public FiniteDifferenceIma
292292

293293
bool m_Touched;
294294

295-
std::vector<bool> m_TouchedForThread;
295+
// NB: although semantically boolean, vector<bool> is not thread safe due to the possibility of multiple bits being
296+
// packed together in the same memory location.
297+
std::vector<uint8_t> m_TouchedForThread;
296298

297299
ValueType m_IsoSurfaceValue;
298300

0 commit comments

Comments
 (0)