@@ -407,7 +407,7 @@ \subsection{Multi-Threading}
407407that do not overlap for write operations.
408408\code {ImageSource}'s \code {GenerateData()} passes \code {this} pointer
409409to \code {ParallelizeImageRegion}, which allows \code {ParallelizeImageRegion}
410- to update the filter's progress after each region is finished processing .
410+ to update the filter's progress after each region has been processed .
411411
412412If a filter has some serial part in the middle, in addition to initialization
413413done in \code {BeforeThreadedGenerateData()} and finalization done in
@@ -424,19 +424,21 @@ \subsection{Multi-Threading}
424424 // Small serial section
425425 this->UpdateProgress(0.01f);
426426
427+ ProgressTransformer progress1( 0.01f, 0.45f, this );
427428 // Calculate 2nd order directional derivative
428429 this->GetMultiThreader()->template ParallelizeImageRegion<TOutputImage::ImageDimension>(
429430 this->GetOutput()->GetRequestedRegion(),
430431 [this](const OutputImageRegionType & outputRegionForThread)
431- { this->ThreadedCompute2ndDerivative(outputRegionForThread); }, nullptr);
432- this->UpdateProgress(0.45f );
432+ { this->ThreadedCompute2ndDerivative(outputRegionForThread); },
433+ progress1.GetProcessObject() );
433434
435+ ProgressTransformer progress2( 0.45f, 0.9f, this );
434436 // Calculate the gradient of the second derivative
435437 this->GetMultiThreader()->template ParallelizeImageRegion<TOutputImage::ImageDimension>(
436438 this->GetOutput()->GetRequestedRegion(),
437439 [this](const OutputImageRegionType & outputRegionForThread)
438- { this->ThreadedCompute2ndDerivativePos(outputRegionForThread); }, nullptr);
439- this->UpdateProgress(0.9f );
440+ { this->ThreadedCompute2ndDerivativePos(outputRegionForThread); },
441+ progress2.GetProcessObject() );
440442
441443 // More processing
442444 this->UpdateProgress(1.0f);
@@ -445,12 +447,13 @@ \subsection{Multi-Threading}
445447\normalsize
446448
447449When invoking \code {ParallelizeImageRegion} multiple times from
448- \code {GenerateData()}, \code {nullptr} should be passed instead of \code {this},
450+ \code {GenerateData()}, either \code {nullptr} or a
451+ \doxygen {ProgressTransformer} object should be passed instead of \code {this},
449452otherwise progress will go from 0\% to 100\% more than once. And this
450453will at least confuse any other class watching the filter's progress events,
451454even if it does not cause a crash. So the filter's author should estimate
452- how long each part of \code {GenerateData()} takes, and update the progress
453- `` manually '' as in the example above.
455+ how long each part of \code {GenerateData()} takes, and construct and pass
456+ \code {ProgressTransformer} objects as in the example above.
454457
455458With ITK version 5.0, the Multi-Threading mechanism has been refactored.
456459What was previously \code {itk::MultiThreader}, is now a hierarchy of classes.
@@ -470,6 +473,15 @@ \subsection{Multi-Threading}
470473the filter's user or downstream filter in the pipeline. The best place for
471474invoking \code {this->DynamicMultiThreadingOff();} is the filter's constructor.
472475
476+ In image filters and other descendants of \code {ProcessObject}, method
477+ \code {SetNumberOfWorkUnits} controls the level of parallelism.
478+ Load balancing is possible when \code {NumberOfWorkUnits} is greater
479+ than the number of threads. In most places where developer would like to
480+ restrict number of threads, work units should be changed instead.
481+ \doxygen {MultiThreaderBase}'s \code {MaximumNumberOfThreads} should not
482+ generally be changed, except when testing performance and scalability,
483+ profiling and sometimes debugging code.
484+
473485The general philosophy in ITK regarding thread safety is that accessing
474486different instances of a class (and its methods) is a thread-safe operation.
475487Invoking methods on the same instance in different threads is to be avoided.
0 commit comments