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
|