/*========================================================================= * * 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. * *=========================================================================*/ /*========================================================================= * * Portions of this file are subject to the VTK Toolkit Version 3 copyright. * * Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen * * For complete copyright, license and disclaimer of warranty information * please refer to the NOTICE file at the top of the ITK source tree. * *=========================================================================*/ #ifndef itkPlatformMultiThreader_h #define itkPlatformMultiThreader_h #include "itkMultiThreaderBase.h" #include #include namespace itk { /** \class PlatformMultiThreader * \brief A class for performing multithreaded execution * * Multithreader is a class that provides support for multithreaded * execution using Windows or POSIX threads. * This class can be used to execute a single * method on multiple threads, or to specify a method per thread. * * \ingroup OSSystemObjects * * \ingroup ITKCommon */ class ITKCommon_EXPORT PlatformMultiThreader : public MultiThreaderBase { public: ITK_DISALLOW_COPY_AND_MOVE(PlatformMultiThreader); /** Standard class type aliases. */ using Self = PlatformMultiThreader; using Superclass = MultiThreaderBase; using Pointer = SmartPointer; using ConstPointer = SmartPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** \see LightObject::GetNameOfClass() */ itkOverrideGetNameOfClassMacro(PlatformMultiThreader); #if !defined(ITK_LEGACY_REMOVE) /** Set/Get the maximum number of threads to use when multithreading. It * will be clamped to the range [ 1, ITK_MAX_THREADS ] because several arrays * are already statically allocated using the ITK_MAX_THREADS number. * Therefore the caller of this method should check that the requested number * of threads was accepted. Legacy: use MultiThreaderBase to invoke these. */ itkLegacyMacro(static void SetGlobalMaximumNumberOfThreads(ThreadIdType val)) { itkGenericOutputMacro("Warning: SetGlobalMaximumNumberOfThreads should now be called on itk::MultiThreaderBase. It " "can affect all MultiThreaderBase's derived classes in ITK"); Superclass::SetGlobalMaximumNumberOfThreads(val); } itkLegacyMacro(static ThreadIdType GetGlobalMaximumNumberOfThreads()) { itkGenericOutputMacro("Warning: GetGlobalMaximumNumberOfThreads should now be called on itk::MultiThreaderBase. It " "can affect all MultiThreaderBase's derived classes in ITK"); return Superclass::GetGlobalMaximumNumberOfThreads(); } /** Set/Get the value which is used to initialize the NumberOfThreads in the * constructor. It will be clamped to the range [1, m_GlobalMaximumNumberOfThreads ]. * Therefore the caller of this method should check that the requested number * of threads was accepted. Legacy: use MultiThreaderBase to invoke these. */ itkLegacyMacro(static void SetGlobalDefaultNumberOfThreads(ThreadIdType val)) { itkGenericOutputMacro("Warning: SetGlobalDefaultNumberOfThreads should now be called on itk::MultiThreaderBase. It " "can affect all MultiThreaderBase's derived classes in ITK"); Superclass::SetGlobalDefaultNumberOfThreads(val); } itkLegacyMacro(static ThreadIdType GetGlobalDefaultNumberOfThreads()) { itkGenericOutputMacro("Warning: GetGlobalDefaultNumberOfThreads should now be called on itk::MultiThreaderBase. It " "can affect all MultiThreaderBase's derived classes in ITK"); return Superclass::GetGlobalDefaultNumberOfThreads(); } #endif /** Execute the SingleMethod (as define by SetSingleMethod) using * m_NumberOfWorkUnits threads. As a side effect the m_NumberOfWorkUnits will be * checked against the current m_GlobalMaximumNumberOfThreads and clamped if * necessary. */ void SingleMethodExecute() override; /** Execute the MultipleMethods (as define by calling SetMultipleMethod for * each of the required m_NumberOfWorkUnits methods) using m_NumberOfWorkUnits * threads. As a side effect the m_NumberOfWorkUnits will be checked against the * current m_GlobalMaximumNumberOfThreads and clamped if necessary. */ itkLegacyMacro(void MultipleMethodExecute()); /** Set the SingleMethod to f() and the UserData field of the * WorkUnitInfo that is passed to it will be data. * This method (and all the methods passed to SetMultipleMethod) * must be of type itkThreadFunctionType and must take a single argument of * type void *. */ void SetSingleMethod(ThreadFunctionType, void * data) override; /** Set the MultipleMethod at the given index to f() and the UserData * field of the WorkUnitInfo that is passed to it will be data. */ itkLegacyMacro(void SetMultipleMethod(ThreadIdType index, ThreadFunctionType, void * data)); /** Create a new thread for the given function. Return a thread id * which is a number between 0 and ITK_MAX_THREADS - 1. This * id should be used to kill the thread at a later time. * Deprecated. Use C++11 thread support instead. */ itkLegacyMacro(ThreadIdType SpawnThread(ThreadFunctionType, void * data)); /** Terminate the thread that was created with a SpawnThreadExecute() * Deprecated. Use C++11 thread support instead. */ itkLegacyMacro(void TerminateThread(ThreadIdType thread_id)); void SetMaximumNumberOfThreads(ThreadIdType numberOfThreads) override; void SetNumberOfWorkUnits(ThreadIdType numberOfWorkUnits) override; struct WorkUnitInfo : MultiThreaderBase::WorkUnitInfo { int * ActiveFlag = nullptr; std::shared_ptr ActiveFlagLock; }; protected: PlatformMultiThreader(); ~PlatformMultiThreader() override; void PrintSelf(std::ostream & os, Indent indent) const override; private: /** An array of thread info containing a thread id * (0, 1, 2, .. ITK_MAX_THREADS-1), the thread count, and a pointer * to void so that user data can be passed to each thread. */ WorkUnitInfo m_ThreadInfoArray[ITK_MAX_THREADS]{}; /** Storage of MutexFunctions and ints used to control spawned * threads and the spawned thread ids. */ int m_SpawnedThreadActiveFlag[ITK_MAX_THREADS]{}; std::shared_ptr m_SpawnedThreadActiveFlagMutex[ITK_MAX_THREADS]{}; ThreadProcessIdType m_SpawnedThreadProcessID[ITK_MAX_THREADS]{}; WorkUnitInfo m_SpawnedThreadInfoArray[ITK_MAX_THREADS]{}; #if !defined(ITK_LEGACY_REMOVE) /** The methods to invoke. */ ThreadFunctionType m_MultipleMethod[ITK_MAX_THREADS]{}; /** Internal storage of the data. */ void * m_MultipleData[ITK_MAX_THREADS]{}; #endif /** spawn a new thread for the SingleMethod */ ThreadProcessIdType SpawnDispatchSingleMethodThread(WorkUnitInfo *); /** wait for a thread in the threadpool to finish work */ void SpawnWaitForSingleMethodThread(ThreadProcessIdType); /** Friends of Multithreader. * ProcessObject is a friend so that it can call PrintSelf() on its * Multithreader. */ friend class ProcessObject; }; } // end namespace itk #endif // itkPlatformMultiThreader_h