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