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_hxx
19 #define itkDomainThreader_hxx
20 
21 #include "itkDomainThreader.h"
22 
23 namespace itk
24 {
25 
26 template< typename TDomainPartitioner, typename TAssociate >
27 DomainThreader< TDomainPartitioner, TAssociate >
DomainThreader()28 ::DomainThreader()
29   : m_Associate(nullptr)
30 
31 {
32   this->m_DomainPartitioner = DomainPartitionerType::New();
33   this->m_MultiThreader = MultiThreaderBase::New();
34   this->m_NumberOfWorkUnits = this->m_MultiThreader->GetNumberOfWorkUnits();
35 }
36 
37 template< typename TDomainPartitioner, typename TAssociate >
38 MultiThreaderBase *
39 DomainThreader< TDomainPartitioner, TAssociate >
GetMultiThreader() const40 ::GetMultiThreader() const
41 {
42   return this->m_MultiThreader;
43 }
44 
45 template< typename TDomainPartitioner, typename TAssociate >
46 void
47 DomainThreader< TDomainPartitioner, TAssociate >
SetMaximumNumberOfThreads(const ThreadIdType threads)48 ::SetMaximumNumberOfThreads( const ThreadIdType threads )
49 {
50   if( threads != this->GetMaximumNumberOfThreads() )
51     {
52     this->m_MultiThreader->SetMaximumNumberOfThreads( threads );
53     this->Modified();
54     }
55 }
56 
57 template< typename TDomainPartitioner, typename TAssociate >
58 void
59 DomainThreader< TDomainPartitioner, TAssociate >
Execute(TAssociate * enclosingClass,const DomainType & completeDomain)60 ::Execute( TAssociate * enclosingClass, const DomainType & completeDomain )
61 {
62   this->m_Associate = enclosingClass;
63   this->m_CompleteDomain = completeDomain;
64 
65   this->DetermineNumberOfWorkUnitsUsed();
66 
67   this->BeforeThreadedExecution();
68 
69   // This calls ThreadedExecution in each thread.
70   this->StartThreadingSequence();
71 
72   this->AfterThreadedExecution();
73 }
74 
75 template< typename TDomainPartitioner, typename TAssociate >
76 void
77 DomainThreader< TDomainPartitioner, TAssociate >
DetermineNumberOfWorkUnitsUsed()78 ::DetermineNumberOfWorkUnitsUsed()
79 {
80   ThreadIdType numberOfWorkUnits = this->GetNumberOfWorkUnits();
81 
82   // Attempt a single dummy partition, just to get the number of subdomains actually created
83   DomainType subdomain;
84   this->m_NumberOfWorkUnitsUsed = this->m_DomainPartitioner->PartitionDomain(0,
85                                             numberOfWorkUnits,
86                                             this->m_CompleteDomain,
87                                             subdomain);
88 
89   this->GetMultiThreader()->SetNumberOfWorkUnits(this->m_NumberOfWorkUnitsUsed);
90 
91   if( this->m_NumberOfWorkUnitsUsed > numberOfWorkUnits )
92     {
93     itkExceptionMacro( "A subclass of ThreadedDomainPartitioner::PartitionDomain"
94                       << "returned more subdomains than were requested" );
95     }
96 }
97 
98 template< typename TDomainPartitioner, typename TAssociate >
99 void
100 DomainThreader< TDomainPartitioner, TAssociate >
StartThreadingSequence()101 ::StartThreadingSequence()
102 {
103   // Set up the multithreaded processing
104   ThreadStruct str;
105   str.domainThreader = this;
106 
107   MultiThreaderBase* multiThreader = this->GetMultiThreader();
108   multiThreader->SetSingleMethod(this->ThreaderCallback, &str);
109 
110   // multithread the execution
111   multiThreader->SingleMethodExecute();
112 }
113 
114 template< typename TDomainPartitioner, typename TAssociate >
115 ITK_THREAD_RETURN_FUNCTION_CALL_CONVENTION
116 DomainThreader< TDomainPartitioner, TAssociate >
ThreaderCallback(void * arg)117 ::ThreaderCallback( void* arg )
118 {
119   auto * info = static_cast<MultiThreaderBase::WorkUnitInfo *>(arg);
120   auto * str = static_cast<ThreadStruct *>(info->UserData);
121   DomainThreader *thisDomainThreader = str->domainThreader;
122   const ThreadIdType threadId    = info->WorkUnitID;
123   const ThreadIdType threadCount = info->NumberOfWorkUnits;
124 
125   // Get the sub-domain to process for this thread.
126   DomainType subdomain;
127   const ThreadIdType total = thisDomainThreader->GetDomainPartitioner()->PartitionDomain(threadId,
128                                             threadCount,
129                                             thisDomainThreader->m_CompleteDomain,
130                                             subdomain);
131 
132   // Execute the actual method with appropriate sub-domain.
133   // If the threadId is greater than the total number of regions
134   // that PartitionDomain will create, don't use this thread.
135   // Sometimes the threads dont break up very well and it is just
136   // as efficient to leave a few threads idle.
137   if ( threadId < total )
138     {
139     thisDomainThreader->ThreadedExecution( subdomain, threadId );
140     }
141 
142   return ITK_THREAD_RETURN_DEFAULT_VALUE;
143 }
144 }
145 
146 #endif
147