@@ -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,16 @@ \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 `ProcessObject`, method
477+ `SetNumberOfThreads` has been renamed into `SetNumberOfWorkUnits`.
478+ For `MultiThreaderBase` and descendants, `SetNumberOfThreads` has been
479+ split into `SetMaximumNumberOfThreads` and `SetNumberOfWorkUnits`.
480+ Load balancing is possible when `NumberOfWorkUnits` is greater
481+ than the number of threads. In most places where number of threads was
482+ being manipulated before, work units shoud be accessed or changed now.
483+ `MaximumNumberOfThreads` should not generally be changed, except when
484+ testing performance and scalability, profilng and sometimes debugging code.
485+
473486The general philosophy in ITK regarding thread safety is that accessing
474487different instances of a class (and its methods) is a thread-safe operation.
475488Invoking methods on the same instance in different threads is to be avoided.
0 commit comments