/*========================================================================= * * 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_hxx #define itkDomainThreader_hxx namespace itk { template DomainThreader::DomainThreader() : m_Associate(nullptr) { this->m_DomainPartitioner = DomainPartitionerType::New(); this->m_MultiThreader = MultiThreaderBase::New(); this->m_NumberOfWorkUnits = this->m_MultiThreader->GetNumberOfWorkUnits(); } template MultiThreaderBase * DomainThreader::GetMultiThreader() const { return this->m_MultiThreader; } template void DomainThreader::SetMaximumNumberOfThreads(const ThreadIdType threads) { if (threads != this->GetMaximumNumberOfThreads()) { this->m_MultiThreader->SetMaximumNumberOfThreads(threads); this->Modified(); } } template void DomainThreader::Execute(TAssociate * enclosingClass, const DomainType & completeDomain) { this->m_Associate = enclosingClass; this->m_CompleteDomain = completeDomain; this->DetermineNumberOfWorkUnitsUsed(); this->BeforeThreadedExecution(); // This calls ThreadedExecution in each thread. this->StartThreadingSequence(); this->AfterThreadedExecution(); } template void DomainThreader::DetermineNumberOfWorkUnitsUsed() { ThreadIdType numberOfWorkUnits = this->GetNumberOfWorkUnits(); // Attempt a single dummy partition, just to get the number of subdomains actually created DomainType subdomain; this->m_NumberOfWorkUnitsUsed = this->m_DomainPartitioner->PartitionDomain(0, numberOfWorkUnits, this->m_CompleteDomain, subdomain); this->GetMultiThreader()->SetNumberOfWorkUnits(this->m_NumberOfWorkUnitsUsed); if (this->m_NumberOfWorkUnitsUsed > numberOfWorkUnits) { itkExceptionMacro( "A subclass of ThreadedDomainPartitioner::PartitionDomain returned more subdomains than were requested"); } } template void DomainThreader::StartThreadingSequence() { // Set up the multithreaded processing ThreadStruct str; str.domainThreader = this; this->GetMultiThreader()->SetSingleMethodAndExecute(this->ThreaderCallback, &str); } template ITK_THREAD_RETURN_FUNCTION_CALL_CONVENTION DomainThreader::ThreaderCallback(void * arg) { auto * info = static_cast(arg); auto * str = static_cast(info->UserData); DomainThreader * thisDomainThreader = str->domainThreader; const ThreadIdType workUnitID = info->WorkUnitID; const ThreadIdType workUnitCount = info->NumberOfWorkUnits; // Get the sub-domain to process for this thread. DomainType subdomain; const ThreadIdType total = thisDomainThreader->GetDomainPartitioner()->PartitionDomain( workUnitID, workUnitCount, thisDomainThreader->m_CompleteDomain, subdomain); // Execute the actual method with appropriate sub-domain. // If the work unit ID is greater than the total number of regions // that PartitionDomain will create, don't use this thread. // Sometimes the threads don't break up very well and it is just // as efficient to leave a few threads idle. if (workUnitID < total) { thisDomainThreader->ThreadedExecution(subdomain, workUnitID); } return ITK_THREAD_RETURN_DEFAULT_VALUE; } } // namespace itk #endif