Skip to content

Commit d5cfd14

Browse files
committed
ENH: mention work units and use ProgressTransformer in the example
1 parent a60a211 commit d5cfd14

File tree

2 files changed

+28
-8
lines changed

2 files changed

+28
-8
lines changed

SoftwareGuide/Latex/Architecture/SystemOverview.tex

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ \subsection{Multi-Threading}
407407
that do not overlap for write operations.
408408
\code{ImageSource}'s \code{GenerateData()} passes \code{this} pointer
409409
to \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

412412
If a filter has some serial part in the middle, in addition to initialization
413413
done 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

447449
When 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},
449452
otherwise progress will go from 0\% to 100\% more than once. And this
450453
will at least confuse any other class watching the filter's progress events,
451454
even 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

455458
With ITK version 5.0, the Multi-Threading mechanism has been refactored.
456459
What was previously \code{itk::MultiThreader}, is now a hierarchy of classes.
@@ -470,6 +473,16 @@ \subsection{Multi-Threading}
470473
the filter's user or downstream filter in the pipeline. The best place for
471474
invoking \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+
473486
The general philosophy in ITK regarding thread safety is that accessing
474487
different instances of a class (and its methods) is a thread-safe operation.
475488
Invoking methods on the same instance in different threads is to be avoided.

SoftwareGuide/Latex/DevelopmentGuidelines/WriteAFilter.tex

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,13 @@ \section{Threaded Filter Execution}
478478
If more than one thread tries to write to the same place at the same time,
479479
the program can behave badly, and possibly even deadlock or crash.
480480

481+
In ITK version 5.0, `DynamicThreadedGenerateData` signature was introduced.
482+
This allows number of pieces (output regions) to be processed to be different,
483+
usually bigger than the number of real threads executing the work. In turn,
484+
this allows load balancing. The number of pieces has been renamed into
485+
work units, and the name `threads' is now reserved for real threads,
486+
as exposed by \doxygen{MultiThreaderBase} and descendants.
487+
481488
Filters which need thread identifier (id) should implement the
482489
\code{ThreadedGenerateData(Region, ThreadId)} method and call
483490
\code{this->DynamicMultiThreadingOff();} in the filter's constructor.

0 commit comments

Comments
 (0)