Skip to content

Commit

Permalink
BUG: fixed issue InsightSoftwareConsortium#3032: fixed mutation from …
Browse files Browse the repository at this point in the history
…several threads simultaneously

The itkSingleLevelSetsv4DenseImage2DTest (and others) fail under TSan because an std::map was mutated from several threads at once.

Fixed by using compare_exchange_strong() to create a thread safe way.
  • Loading branch information
seanm committed Jan 12, 2022
1 parent 38d385b commit d3bf262
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
#include "itkLevelSetEquationTermBase.h"
#include "itkObject.h"

#include <unordered_map>

#include <atomic>
#include <map>
#include <string>
#include <unordered_map>

namespace itk
{
Expand Down Expand Up @@ -320,7 +320,7 @@ class ITK_TEMPLATE_EXPORT LevelSetEquationTermContainer : public Object

MapTermContainerType m_Container;

using MapCFLContainerType = std::map<TermIdType, LevelSetOutputRealType>;
using MapCFLContainerType = std::map<TermIdType, std::atomic<LevelSetOutputRealType>>;
using MapCFLContainerIterator = typename MapCFLContainerType::iterator;
using MapCFLContainerConstIterator = typename MapCFLContainerType::const_iterator;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,14 @@ LevelSetEquationTermContainer<TInputImage, TLevelSetContainer>::Evaluate(const L
{
LevelSetOutputRealType temp_val = (term_it->second)->Evaluate(iP);

cfl_it->second = std::max(itk::Math::abs(temp_val), cfl_it->second);
LevelSetOutputRealType abs_temp_value = itk::Math::abs(temp_val);

// This is a thread-safe equivalent of:
// cfl_it->second = std::max(abs_temp_value, cfl_it->second);
LevelSetOutputRealType previous_value = cfl_it->second;
while ((abs_temp_value > previous_value) && !cfl_it->second.compare_exchange_strong(previous_value, abs_temp_value))
{
}

oValue += temp_val;
++term_it;
Expand All @@ -298,7 +305,14 @@ LevelSetEquationTermContainer<TInputImage, TLevelSetContainer>::Evaluate(const L
{
LevelSetOutputRealType temp_val = (term_it->second)->Evaluate(iP, iData);

cfl_it->second = std::max(itk::Math::abs(temp_val), cfl_it->second);
LevelSetOutputRealType abs_temp_value = itk::Math::abs(temp_val);

// This is a thread-safe equivalent of:
// cfl_it->second = std::max(abs_temp_value, cfl_it->second);
LevelSetOutputRealType previous_value = cfl_it->second;
while ((abs_temp_value > previous_value) && !cfl_it->second.compare_exchange_strong(previous_value, abs_temp_value))
{
}

oValue += temp_val;
++term_it;
Expand Down

0 comments on commit d3bf262

Please sign in to comment.