File: itkDomainThreader.h

package info (click to toggle)
insighttoolkit5 5.4.3-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 704,384 kB
  • sloc: cpp: 783,592; ansic: 628,724; xml: 44,704; fortran: 34,250; python: 22,874; sh: 4,078; pascal: 2,636; lisp: 2,158; makefile: 464; yacc: 328; asm: 205; perl: 203; lex: 146; tcl: 132; javascript: 98; csh: 81
file content (195 lines) | stat: -rw-r--r-- 7,412 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/*=========================================================================
 *
 *  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
 *
 *         https://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.
 *
 *=========================================================================*/
#ifndef itkDomainThreader_h
#define itkDomainThreader_h

#include "itkObject.h"
#include "itkMultiThreaderBase.h"

namespace itk
{

/** \class DomainThreader
 *  \brief Multi-threaded processing on a domain by processing sub-domains per
 *  thread.
 *
 *  This class uses a ThreadedDomainPartitioner as a helper to split the
 *  domain into subdomains.  Each subdomain is then processed in the
 *  \c ThreadedExecution method.
 *
 *  The data on which to perform the processing is assumed to be members
 *  of an associating class.  Therefore, to perform a threaded operation in a
 *  class, the associating class usually will declare derived versions of this
 *  class as a friend class.
 *
 *  To use this class, at a minimum,
 *  \li Inherit from it.
 *  \li Implement ThreadedExecution.
 *  \li Create a member instance.
 *  \li Run with m_DomainThreader->Execute( this, domain );
 *
 *  If a 'threaded method' is desired to perform some data processing in a
 *  class, a derived version of this class can be defined to perform the threaded operation.
 *  Since a threaded operation is relatively complex compared to a simple serial
 *  operation, a class instead of a simple method is required.  Inside this
 *  class, the method to partition the data is handled, the logic for
 *  deciding the number of work units is determined, and operations surrounding
 *  the threading are encapsulated into the class with the
 *  \c DetermineNumberOfWorkUnitsToUse, \c BeforeThreadedExecution, \c ThreadedExecution,
 *  and \c AfterThreadedExecution virtual methods.
 *
 *  \tparam TDomainPartitioner A class that inherits from
 *  ThreadedDomainPartitioner.
 *  \tparam TAssociate  The associated class that uses a derived version of
 *  this class as a "threaded method".  The associated class usually declares
 *  derived version of this class as nested classes so there is easy access to
 *  its protected and private members in ThreadedExecution.
 *
 *  \ingroup ITKCommon
 */
template <typename TDomainPartitioner, typename TAssociate>
class ITK_TEMPLATE_EXPORT DomainThreader : public Object
{
public:
  ITK_DISALLOW_COPY_AND_MOVE(DomainThreader);

  /** Standard class type aliases. */
  using Self = DomainThreader;
  using Superclass = Object;
  using Pointer = SmartPointer<Self>;
  using ConstPointer = SmartPointer<const Self>;

  using DomainPartitionerType = TDomainPartitioner;
  using DomainType = typename DomainPartitionerType::DomainType;

  using AssociateType = TAssociate;

  /** \see LightObject::GetNameOfClass() */
  itkOverrideGetNameOfClassMacro(DomainThreader);

  /** Run the multi-threaded operation on the given domain.
   *
   * The domain is first partitioned by the ThreadedDomainPartitioner, then
   * the virtual methods \c BeforeThreadedExecution, \c ThreadedExecution, and
   * \c AfterThreadedExecution. are run, in order. */
  void
  Execute(AssociateType * enclosingClass, const DomainType & completeDomain);

  /** Set/Get the DomainPartitioner. */
  itkSetObjectMacro(DomainPartitioner, DomainPartitionerType);
  itkGetModifiableObjectMacro(DomainPartitioner, DomainPartitionerType);

  /** Accessor for number of work units that were actually used in the last
   * ThreadedExecution. */
  itkGetConstMacro(NumberOfWorkUnitsUsed, ThreadIdType);

  /** Return the multithreader used by this class. */
  MultiThreaderBase *
  GetMultiThreader() const;

  /** Convenience methods to set/get the desired number of work units to use.
   * \warning When setting the desired number of work units, it might be clamped by
   * itk::MultiThreaderBase::GetGlobalMaximumNumberOfThreads().
   * */
  itkSetClampMacro(NumberOfWorkUnits, ThreadIdType, 1, ITK_MAX_THREADS);
  itkGetConstMacro(NumberOfWorkUnits, ThreadIdType);

  /** Convenience methods to set/get the maximum number of threads to use.
   * \warning When setting the maximum number of threads, it will be clamped by
   * itk::MultiThreaderBase::GetGlobalMaximumNumberOfThreads().
   * */
  ThreadIdType
  GetMaximumNumberOfThreads() const
  {
    return this->m_MultiThreader->GetMaximumNumberOfThreads();
  }
  void
  SetMaximumNumberOfThreads(const ThreadIdType threads);

protected:
  DomainThreader();
  ~DomainThreader() override = default;

  /** This is evaluated at the beginning of Execute() so that it can be used in
   * BeforeThreadedExecution(). */
  virtual void
  DetermineNumberOfWorkUnitsUsed();

  /** When \c Execute is run, this method is run singled-threaded before \c
   * ThreadedExecution.  Inside this method optional operations such as
   * creating instance variables needed per thread may be performed. */
  virtual void
  BeforeThreadedExecution()
  {}

  /** Do the threaded operation, somewhat like \c ThreadedGenerateData in an
   * ImageSource.
   * \param subdomain The subdomain to operate on.
   * \param threadId  The identifier for the current thread.
   * Data to perform the operation on can be accessed by dereferencing
   * this->m_Associate, which has direct access to private and protected
   * members the enclosing class.
   */
  virtual void
  ThreadedExecution(const DomainType & subdomain, const ThreadIdType threadId) = 0;

  /** When \c Execute in run, this method is run single-threaded after \c
   * ThreadedExecution.  Optionally collect results, etc. E.g. calculate the
   * global minimum from the minimums calculated per thread. */
  virtual void
  AfterThreadedExecution()
  {}

  itkSetObjectMacro(MultiThreader, MultiThreaderBase);

  /** Static function used as a "callback" by the MultiThreaderBase.  The threading
   * library will call this routine for each thread, which will delegate the
   * control to the ThreadFunctor. */
  static ITK_THREAD_RETURN_FUNCTION_CALL_CONVENTION
  ThreaderCallback(void * arg);

  AssociateType * m_Associate{};

private:
  void
  StartThreadingSequence();

  /** This contains the object passed to the threading library. */
  struct ThreadStruct
  {
    DomainThreader * domainThreader;
  };

  /** Store the actual number of work units used, which may be less than
   * the number allocated by the threader if the object does not split
   * well into that number.
   * This value is determined at the beginning of \c Execute(). */
  ThreadIdType                            m_NumberOfWorkUnitsUsed{ 0 };
  ThreadIdType                            m_NumberOfWorkUnits{};
  typename DomainPartitionerType::Pointer m_DomainPartitioner{};
  DomainType                              m_CompleteDomain{};
  MultiThreaderBase::Pointer              m_MultiThreader{};
};

} // namespace itk

#ifndef ITK_MANUAL_INSTANTIATION
#  include "itkDomainThreader.hxx"
#endif

#endif