Repository: InsightSoftwareConsortium/ITK (C++)

Issue:
Exception not caught with PoolMultiThreader if not in main task
### Description

An exception is launched but not caught by PoolMultiThreader when the exception is not launched by the main task.

### Steps to Reproduce

I have written the following minimal example to reproduce the issue:

```cpp
#include <itkImageSource.h>

namespace itk
{
template <typename TOutputImage>
class ITK_TEMPLATE_EXPORT DummyImageSource
  : public ImageSource<TOutputImage>
{
public:
  ITK_DISALLOW_COPY_AND_MOVE(DummyImageSource);

  /** Standard class type aliases. */
  using Self = DummyImageSource;
  using Superclass = ImageSource<TOutputImage>;
  using Pointer = SmartPointer<Self>;
  using ConstPointer = SmartPointer<const Self>;

  /** Convenient type alias. */
  using OutputImageRegionType = typename TOutputImage::RegionType;

  /** Method for creation through the object factory. */
  itkNewMacro(Self);

  /** Run-time type information (and related methods). */
  itkTypeMacro(DummyImageSource, ImageSource);

protected:
  DummyImageSource() = default;
  ~DummyImageSource() override = default;
  void GenerateOutputInformation() override
  {
  TOutputImage * output = nullptr;
  output = this->GetOutput(0);
  typename TOutputImage::RegionType largestPossibleRegion;
  largestPossibleRegion.SetSize({4,4,4});
  output->SetLargestPossibleRegion(largestPossibleRegion);
  }

  void
  DynamicThreadedGenerateData(const OutputImageRegionType & outputRegionForThread) override
  {
    if(outputRegionForThread.GetIndex() != typename TOutputImage::IndexType())
    {
      std::cout << "Exception launched" << std::endl;
      itkGenericExceptionMacro(<< "Error");
    }
  }
};
} // end namespace itk

int
main(int argc, char * argv[])
{
  using OutputPixelType = float;
  constexpr unsigned int Dimension = 3;

  using OutputImageType = itk::Image<OutputPixelType, Dimension>;

  typename itk::DummyImageSource<OutputImageType>::Pointer dummySrc;
  dummySrc = itk::DummyImageSource<OutputImageType>::New();
  try
  {
    dummySrc->Update();
  }
  catch (itk::ExceptionObject & err)
  {
    std::cerr << "Problem!!!" << std::endl;
    return EXIT_FAILURE;
  }
  std::cout << "No problem" << std::endl;
  return EXIT_SUCCESS;
}
```
### Expected behavior

The following should be displayed
```
Exception launched
Exception launched
Exception launched
Problem!!!
```
which occurs with the environment variable ITK_GLOBAL_DEFAULT_THREADER=PLATFORM

### Actual behavior

<!-- What actually happens. Include the relevant build error trace. -->
```
Exception launched
Exception launched
Exception launched
No problem
```

### Reproducibility

100%

### Versions

eec9fe6705

### Environment

Linux

### Additional Information



Discussion:
Bug introduced by 181171da2146b3a17fb15028627e592ed0627841



Patch:
diff --git a/Modules/Core/Common/src/itkPoolMultiThreader.cxx b/Modules/Core/Common/src/itkPoolMultiThreader.cxx
index 8c3087621bb..dfab46b82cd 100644
--- a/Modules/Core/Common/src/itkPoolMultiThreader.cxx
+++ b/Modules/Core/Common/src/itkPoolMultiThreader.cxx
@@ -302,6 +302,7 @@ PoolMultiThreader::ParallelizeImageRegion(unsigned int         dimension,
               filter->IncrementProgress(0);
             }
           } while (status != std::future_status::ready);
+          m_ThreadInfoArray[i].Future.get();
           reporter.CompletedPixel();
         });
       }


Test patch:
diff --git a/Modules/Core/Common/test/CMakeLists.txt b/Modules/Core/Common/test/CMakeLists.txt
index c2398c22cfe..6395ba8b75e 100644
--- a/Modules/Core/Common/test/CMakeLists.txt
+++ b/Modules/Core/Common/test/CMakeLists.txt
@@ -119,6 +119,7 @@ itkMultiThreaderTypeFromEnvironmentTest.cxx
 itkMultiThreadingEnvironmentTest.cxx
 itkMultiThreaderParallelizeArrayTest.cxx
 itkMultithreadingTest.cxx
+itkMultiThreaderExceptionsTest.cxx
 
 itkMetaProgrammingLibraryTest.cxx
 itkPromoteType.cxx
@@ -574,6 +575,8 @@ itk_add_test(NAME itkMetaDataObjectTest COMMAND ITKCommon2TestDriver itkMetaData
 
 itk_add_test(NAME itkMultithreadingTest COMMAND ITKCommon2TestDriver itkMultithreadingTest 100)
 
+itk_add_test(NAME itkMultiThreaderExceptionsTest COMMAND ITKCommon2TestDriver itkMultiThreaderExceptionsTest)
+
 if(ITK_BUILD_SHARED_LIBS AND ITK_DYNAMIC_LOADING)
   macro(BuildClientTestLibrary _name _type)
     add_library(ClientTestLibrary${_name} ${_type} ClientTestLibrary${_name}.cxx)
diff --git a/Modules/Core/Common/test/itkMultiThreaderExceptionsTest.cxx b/Modules/Core/Common/test/itkMultiThreaderExceptionsTest.cxx
new file mode 100644
index 00000000000..ea9bb5bf96e
--- /dev/null
+++ b/Modules/Core/Common/test/itkMultiThreaderExceptionsTest.cxx
@@ -0,0 +1,104 @@
+/*=========================================================================
+ *
+ *  Copyright NumFOCUS
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0.txt
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *=========================================================================*/
+
+#include "itkImageSource.h"
+#include "itkTestingMacros.h"
+
+using ThreaderEnum = itk::MultiThreaderBase::ThreaderEnum;
+
+namespace itk
+{
+template <typename TOutputImage>
+class ITK_TEMPLATE_EXPORT DummyImageSource : public ImageSource<TOutputImage>
+{
+public:
+  ITK_DISALLOW_COPY_AND_MOVE(DummyImageSource);
+
+  /** Standard class type aliases. */
+  using Self = DummyImageSource;
+  using Superclass = ImageSource<TOutputImage>;
+  using Pointer = SmartPointer<Self>;
+  using ConstPointer = SmartPointer<const Self>;
+
+  /** Convenient type alias. */
+  using OutputImageRegionType = typename TOutputImage::RegionType;
+
+  /** Method for creation through the object factory. */
+  itkNewMacro(Self);
+
+  /** Run-time type information (and related methods). */
+  itkTypeMacro(DummyImageSource, ImageSource);
+
+  /** Index for which exception is thrown. */
+  itkSetMacro(ExceptionIndex, IndexValueType);
+
+protected:
+  DummyImageSource() = default;
+  ~DummyImageSource() override = default;
+  void
+  GenerateOutputInformation() override
+  {
+    TOutputImage * output = nullptr;
+    output = this->GetOutput(0);
+    typename TOutputImage::RegionType largestPossibleRegion;
+    largestPossibleRegion.SetSize({ 4 });
+    output->SetLargestPossibleRegion(largestPossibleRegion);
+  }
+
+  void
+  DynamicThreadedGenerateData(const OutputImageRegionType & outputRegionForThread) override
+  {
+    if (outputRegionForThread.GetIndex(0) == m_ExceptionIndex)
+    {
+      std::cout << "Exception launched" << std::endl;
+      itkGenericExceptionMacro(<< "Error");
+    }
+  }
+
+private:
+  IndexValueType m_ExceptionIndex{ 0 };
+};
+} // end namespace itk
+
+int
+itkMultiThreaderExceptionsTest(int, char *[])
+{
+  using OutputPixelType = float;
+  constexpr unsigned int Dimension = 1;
+
+  using OutputImageType = itk::Image<OutputPixelType, Dimension>;
+
+  std::set<ThreaderEnum> threadersToTest = { ThreaderEnum::Platform, ThreaderEnum::Pool };
+#ifdef ITK_USE_TBB
+  threadersToTest.insert(ThreaderEnum::TBB);
+#endif // ITK_USE_TBB
+  for (auto thType : threadersToTest)
+  {
+    itk::MultiThreaderBase::SetGlobalDefaultThreader(thType);
+    typename itk::DummyImageSource<OutputImageType>::Pointer dummySrc;
+    dummySrc = itk::DummyImageSource<OutputImageType>::New();
+    dummySrc->SetNumberOfWorkUnits(4);
+    for (itk::IndexValueType i = 0; i < 4; ++i)
+    {
+      dummySrc->SetExceptionIndex(i);
+      ITK_TRY_EXPECT_EXCEPTION(dummySrc->Update());
+    }
+  }
+  std::cout << "Test PASSED!" << std::endl;
+  return EXIT_SUCCESS;
+}