1 /*========================================================================= 2 * 3 * Copyright Insight Software Consortium 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0.txt 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 *=========================================================================*/ 18 #ifndef itkDomainThreader_h 19 #define itkDomainThreader_h 20 21 #include "itkObject.h" 22 #include "itkMultiThreaderBase.h" 23 24 namespace itk 25 { 26 27 /** \class DomainThreader 28 * \brief Multi-threaded processing on a domain by processing sub-domains per 29 * thread. 30 * 31 * This class uses a ThreadedDomainPartitioner as a helper to split the 32 * domain into subdomains. Each subdomain is then processed in the 33 * \c ThreadedExecution method. 34 * 35 * The data on which to perform the processing is assumed to be members 36 * of an associating class. Therefore, to perform a threaded operation in a 37 * class, the associating class usually will declare derived versions of this 38 * class as a friend class. 39 * 40 * To use this class, at a minimum, 41 * \li Inherit from it. 42 * \li Implement ThreadedExecution. 43 * \li Create a member instance. 44 * \li Run with m_DomainThreader->Execute( this, domain ); 45 * 46 * If a 'threaded method' is desired to perform some data processing in a 47 * class, a derived version of this class can be defined to perform the threaded operation. 48 * Since a threaded operation is relatively complex compared to a simple serial 49 * operation, a class instead of a simple method is required. Inside this 50 * class, the method to partition the data is handled, the logic for 51 * deciding the number of work units is determined, and operations surrounding 52 * the threading are encapsulated into the class with the 53 * \c DetermineNumberOfWorkUnitsToUse, \c BeforeThreadedExecution, \c ThreadedExecution, 54 * and \c AfterThreadedExecution virtual methods. 55 * 56 * \tparam TDomainPartitioner A class that inherits from 57 * ThreadedDomainPartitioner. 58 * \tparam TAssociate The associated class that uses a derived version of 59 * this class as a "threaded method". The associated class usually declares 60 * derived version of this class as nested classes so there is easy access to 61 * its protected and private members in ThreadedExecution. 62 * 63 * \ingroup ITKCommon 64 */ 65 template< typename TDomainPartitioner, typename TAssociate > 66 class ITK_TEMPLATE_EXPORT DomainThreader: public Object 67 { 68 public: 69 ITK_DISALLOW_COPY_AND_ASSIGN(DomainThreader); 70 71 /** Standard class type aliases. */ 72 using Self = DomainThreader; 73 using Superclass = Object; 74 using Pointer = SmartPointer< Self >; 75 using ConstPointer = SmartPointer< const Self >; 76 77 using DomainPartitionerType = TDomainPartitioner; 78 using DomainType = typename DomainPartitionerType::DomainType; 79 80 using AssociateType = TAssociate; 81 82 /** Run-time type information (and related methods). */ 83 itkTypeMacro( DomainThreader, Object ); 84 85 /** Run the multi-threaded operation on the given domain. 86 * 87 * The domain is first partitioned by the ThreadedDomainPartitioner, then 88 * the virtual methods \c BeforeThreadedExecution, \c ThreadedExecution, and 89 * \c AfterThreadedExecution. are run, in order. */ 90 void Execute( AssociateType * enclosingClass, const DomainType & domain ); 91 92 /** Set/Get the DomainPartitioner. */ 93 itkSetObjectMacro( DomainPartitioner, DomainPartitionerType ); 94 itkGetModifiableObjectMacro( DomainPartitioner, DomainPartitionerType ); 95 96 /** Accessor for number of work units that were actually used in the last 97 * ThreadedExecution. */ 98 itkGetConstMacro( NumberOfWorkUnitsUsed, ThreadIdType ); 99 100 /** Return the multithreader used by this class. */ 101 MultiThreaderBase * GetMultiThreader() const; 102 103 /** Convenience methods to set/get the desired number of work units to use. 104 * \warning When setting the desired number of work units, it might be clamped by 105 * itk::MultiThreaderBase::GetGlobalMaximumNumberOfThreads(). 106 * */ 107 itkSetClampMacro(NumberOfWorkUnits, ThreadIdType, 1, ITK_MAX_THREADS); 108 itkGetConstMacro(NumberOfWorkUnits, ThreadIdType); 109 110 /** Convenience methods to set/get the maximum number of threads to use. 111 * \warning When setting the maximum number of threads, it will be clamped by 112 * itk::MultiThreaderBase::GetGlobalMaximumNumberOfThreads(). 113 * */ GetMaximumNumberOfThreads()114 ThreadIdType GetMaximumNumberOfThreads() const 115 { 116 return this->m_MultiThreader->GetMaximumNumberOfThreads(); 117 } 118 void SetMaximumNumberOfThreads(const ThreadIdType threads); 119 120 protected: 121 DomainThreader(); 122 ~DomainThreader() override = default; 123 124 /** This is evauated at the beginning of Execute() so that it can be used in 125 * BeforeThreadedExecution(). */ 126 virtual void DetermineNumberOfWorkUnitsUsed(); 127 128 /** When \c Execute is run, this method is run singled-threaded before \c 129 * ThreadedExecution. Inside this method optional operations such as 130 * creating instance variables needed per thread may be performed. */ BeforeThreadedExecution()131 virtual void BeforeThreadedExecution(){} 132 133 /** Do the threaded operation, somewhat like \c ThreadedGenerateData in an 134 * ImageSource. 135 * \param subdomain The subdomain to operate on. 136 * \param threadId The identifier for the current thread. 137 * Data to perform the operation on can be accessed by dereferencing 138 * this->m_Associate, which has direct access to private and protected 139 * members the enclosing class. 140 */ 141 virtual void ThreadedExecution( const DomainType& subdomain, 142 const ThreadIdType threadId ) = 0; 143 144 /** When \c Execute in run, this method is run single-threaded after \c 145 * ThreadedExecution. Optionally collect results, etc. E.g. calculate the 146 * global minimum from the minimums calculated per thread. */ AfterThreadedExecution()147 virtual void AfterThreadedExecution(){} 148 149 itkSetObjectMacro( MultiThreader, MultiThreaderBase ); 150 151 /** Static function used as a "callback" by the MultiThreaderBase. The threading 152 * library will call this routine for each thread, which will delegate the 153 * control to the ThreadFunctor. */ 154 static ITK_THREAD_RETURN_FUNCTION_CALL_CONVENTION ThreaderCallback( void *arg ); 155 156 AssociateType * m_Associate; 157 158 private: 159 void StartThreadingSequence(); 160 161 /** This contains the object passed to the threading library. */ 162 struct ThreadStruct 163 { 164 DomainThreader * domainThreader; 165 }; 166 167 /** Store the actual number of work units used, which may be less than 168 * the number allocated by the threader if the object does not split 169 * well into that number. 170 * This value is determined at the beginning of \c Execute(). */ 171 ThreadIdType m_NumberOfWorkUnitsUsed{0}; 172 ThreadIdType m_NumberOfWorkUnits; 173 typename DomainPartitionerType::Pointer m_DomainPartitioner; 174 DomainType m_CompleteDomain; 175 MultiThreaderBase::Pointer m_MultiThreader; 176 }; 177 178 } 179 180 #ifndef ITK_MANUAL_INSTANTIATION 181 #include "itkDomainThreader.hxx" 182 #endif 183 184 #endif 185