diff --git a/Modules/Core/Common/ITKKWStyleOverwrite.txt b/Modules/Core/Common/ITKKWStyleOverwrite.txt index c7e6f6b5302..3731bd05528 100644 --- a/Modules/Core/Common/ITKKWStyleOverwrite.txt +++ b/Modules/Core/Common/ITKKWStyleOverwrite.txt @@ -28,3 +28,4 @@ itkIndex\.h SemicolonSpace Disable itkSize\.h SemicolonSpace Disable itkOffset\.h SemicolonSpace Disable itkMultiThreaderBase.h Comments Disable +itkSingleton\.cxx Namespace Disable diff --git a/Modules/Core/Common/include/itkBuildInformation.h b/Modules/Core/Common/include/itkBuildInformation.h index 06aecd887f1..5ba1d21103f 100644 --- a/Modules/Core/Common/include/itkBuildInformation.h +++ b/Modules/Core/Common/include/itkBuildInformation.h @@ -21,6 +21,7 @@ #include "itkMacro.h" #include "itkObject.h" #include +#include "itkSingletonMacro.h" namespace itk { @@ -41,6 +42,8 @@ namespace itk * \ingroup ITKCommon * */ +struct BuildInformationGlobals; + class ITKCommon_EXPORT BuildInformation final: public Object { public: @@ -90,10 +93,9 @@ class ITKCommon_EXPORT BuildInformation final: public Object private: BuildInformation(); - /** To lock on the internal variables */ - static std::mutex m_Mutex; - static Pointer m_InformationInstance; - static MapType m_Map; + itkGetGlobalDeclarationMacro(BuildInformationGlobals, PimplGlobals); + static BuildInformationGlobals * m_PimplGlobals; + }; // end of class } // end namespace itk #endif diff --git a/Modules/Core/Common/include/itkDataObject.h b/Modules/Core/Common/include/itkDataObject.h index 1312e26efdc..a903820a1b6 100644 --- a/Modules/Core/Common/include/itkDataObject.h +++ b/Modules/Core/Common/include/itkDataObject.h @@ -30,6 +30,7 @@ #include "itkObject.h" #include "itkMacro.h" +#include "itkSingletonMacro.h" #include "itkWeakPointer.h" #include "itkRealTimeStamp.h" @@ -504,7 +505,7 @@ class ITK_FORCE_EXPORT_MACRO(ITKCommon) DataObject:public Object ModifiedTimeType m_PipelineMTime; /** Static member that controls global data release after use by filter. */ - static bool m_GlobalReleaseDataFlag; + static bool *m_GlobalReleaseDataFlag; /** Connect the specified process object to the data object. This * should only be called from a process object. The second parameter @@ -522,6 +523,10 @@ class ITK_FORCE_EXPORT_MACRO(ITKCommon) DataObject:public Object * pipeline (see ConnectSource), then nothing is done. */ bool DisconnectSource(ProcessObject *s, const DataObjectIdentifierType & name); + /** Only used to synchronize the global variable across static libraries.*/ + itkGetGlobalDeclarationMacro(bool, GlobalReleaseDataFlag); + + /** Friends of DataObject */ friend class ProcessObject; friend class DataObjectError; diff --git a/Modules/Core/Common/include/itkFloatingPointExceptions.h b/Modules/Core/Common/include/itkFloatingPointExceptions.h index 1e90a0488bd..33ee3f32531 100644 --- a/Modules/Core/Common/include/itkFloatingPointExceptions.h +++ b/Modules/Core/Common/include/itkFloatingPointExceptions.h @@ -19,6 +19,7 @@ #define itkFloatingPointExceptions_h #include "itkMacro.h" // for ITKCommon_EXPORT +#include "itkSingletonMacro.h" namespace itk { @@ -28,6 +29,9 @@ namespace itk * Allows floating point exceptions to be caught during program execution. * \ingroup ITKCommon */ + +struct ExceptionGlobals; + class ITKCommon_EXPORT FloatingPointExceptions { public: @@ -76,9 +80,9 @@ class ITKCommon_EXPORT FloatingPointExceptions FloatingPointExceptions(const FloatingPointExceptions &) = delete; void operator=(const FloatingPointExceptions &) = delete; + itkGetGlobalDeclarationMacro(ExceptionGlobals, PimplGlobals); /** static member that controls what happens during an exception */ - static ExceptionAction m_ExceptionAction; - static bool m_Enabled; + static ExceptionGlobals * m_PimplGlobals; }; } diff --git a/Modules/Core/Common/include/itkMersenneTwisterRandomVariateGenerator.h b/Modules/Core/Common/include/itkMersenneTwisterRandomVariateGenerator.h index b40fe25aa8a..daebc409f43 100644 --- a/Modules/Core/Common/include/itkMersenneTwisterRandomVariateGenerator.h +++ b/Modules/Core/Common/include/itkMersenneTwisterRandomVariateGenerator.h @@ -24,7 +24,7 @@ #include "itkIntTypes.h" #include "itkMath.h" #include -#include +#include "itkSingletonMacro.h" #include #include @@ -119,6 +119,9 @@ namespace Statistics * \wikiexample{Utilities/MersenneTwisterRandomVariateGenerator,Random number generator} * \endwiki */ + +struct MersenneTwisterGlobals; + class ITKCommon_EXPORT MersenneTwisterRandomVariateGenerator: public RandomVariateGeneratorBase { @@ -278,6 +281,9 @@ class ITKCommon_EXPORT MersenneTwisterRandomVariateGenerator: private: + /** Only used to synchronize the global variable across static libraries.*/ + itkGetGlobalDeclarationMacro(MersenneTwisterGlobals, PimplGlobals); + /** Internal method to actually create a new object. */ static Pointer CreateInstance(); @@ -285,9 +291,8 @@ class ITKCommon_EXPORT MersenneTwisterRandomVariateGenerator: std::mutex m_InstanceLock; // Static/Global Variable need to be thread-safely accessed - static Pointer m_StaticInstance; - static std::recursive_mutex m_StaticInstanceLock; - static IntegerType m_StaticDiffer; + + static MersenneTwisterGlobals *m_PimplGlobals; }; // end of class diff --git a/Modules/Core/Common/include/itkMultiThreaderBase.h b/Modules/Core/Common/include/itkMultiThreaderBase.h index 7c1930973c6..359df37f060 100644 --- a/Modules/Core/Common/include/itkMultiThreaderBase.h +++ b/Modules/Core/Common/include/itkMultiThreaderBase.h @@ -34,6 +34,7 @@ #include "itkIntTypes.h" #include "itkImageRegion.h" #include "itkImageIORegion.h" +#include "itkSingletonMacro.h" #include #include @@ -55,7 +56,6 @@ namespace itk */ struct MultiThreaderBaseGlobals; - class ProcessObject; class ITKCommon_EXPORT MultiThreaderBase : public Object @@ -340,14 +340,6 @@ INTEL_PRAGMA_WARN_POP ThreadingFunctorType funcP, ProcessObject* filter); - /** Set/Get the pointer to MultiThreaderBaseGlobals. - * Note that these functions are not part of the public API and should not be - * used outside of ITK. They are an implementation detail and will be - * removed in the future. Also note that SetMultiThreaderBaseGlobals is not - * concurrent thread safe. */ - static MultiThreaderBaseGlobals *GetMultiThreaderBaseGlobals(); - static void SetMultiThreaderBaseGlobals(MultiThreaderBaseGlobals * multiThreaderBaseGlobals); - /** Updates progress if progress is non-negative and checks for abort. * If "abort generate data" is set, throws the ProcessAborted exception. */ static void HandleFilterProgress(ProcessObject *filter, float progress = -1.0f); @@ -411,7 +403,11 @@ INTEL_PRAGMA_WARN_POP void *m_SingleData; private: - static MultiThreaderBaseGlobals * m_MultiThreaderBaseGlobals; + + /** Only used to synchronize the global variable across static libraries.*/ + itkGetGlobalDeclarationMacro(MultiThreaderBaseGlobals, PimplGlobals); + + static MultiThreaderBaseGlobals * m_PimplGlobals; /** Friends of Multithreader. * ProcessObject is a friend so that it can call PrintSelf() on its * Multithreader. */ diff --git a/Modules/Core/Common/include/itkObject.h b/Modules/Core/Common/include/itkObject.h index 9861fadcd74..01af3d166a4 100644 --- a/Modules/Core/Common/include/itkObject.h +++ b/Modules/Core/Common/include/itkObject.h @@ -31,6 +31,7 @@ #include "itkLightObject.h" #include "itkEventObject.h" #include "itkMetaDataDictionary.h" +#include "itkSingletonMacro.h" namespace itk { @@ -202,6 +203,9 @@ class ITKCommon_EXPORT Object:public LightObject virtual void SetTimeStamp( const TimeStamp & time ); private: + /** Only used to synchronize the global variable across static libraries.*/ + itkGetGlobalDeclarationMacro(bool, GlobalWarningDisplay); + /** Enable/Disable debug messages. */ mutable bool m_Debug{false}; @@ -209,7 +213,7 @@ class ITKCommon_EXPORT Object:public LightObject mutable TimeStamp m_MTime; /** Global object debug flag. */ - static bool m_GlobalWarningDisplay; + static bool *m_GlobalWarningDisplay; /** Implementation class for Subject/Observer Pattern. * This is only allocated if used. */ diff --git a/Modules/Core/Common/include/itkObjectFactoryBase.h b/Modules/Core/Common/include/itkObjectFactoryBase.h index cb25127c9da..d3c4dd46b51 100644 --- a/Modules/Core/Common/include/itkObjectFactoryBase.h +++ b/Modules/Core/Common/include/itkObjectFactoryBase.h @@ -29,6 +29,7 @@ #define itkObjectFactoryBase_h #include "itkCreateObjectFunction.h" +#include "itkSingletonMacro.h" #include #include @@ -198,14 +199,6 @@ class ITKCommon_EXPORT ObjectFactoryBase:public Object CreateObjectFunctionBase::Pointer m_CreateObject; }; - /** Set/Get the pointer to ObjectFactoryBasePrivate. - * Note that these functions are not part of the public API and should not be - * used outside of ITK. They are an implementation detail and will be - * removed in the future. Also note that SetObjectFactoryBasePrivate is not - * concurrent thread safe. */ - static ObjectFactoryBasePrivate *GetObjectFactoryBase(); - static void SynchronizeObjectFactoryBase(ObjectFactoryBasePrivate * objectFactoryBasePrivate); - protected: void PrintSelf(std::ostream & os, Indent indent) const override; @@ -231,6 +224,12 @@ class ITKCommon_EXPORT ObjectFactoryBase:public Object ~ObjectFactoryBase() override; private: + + /** Set/Get the pointer to ObjectFactoryBasePrivate. + * No concurrent thread safe. */ + static void SynchronizeObjectFactoryBase(void * objectFactoryBasePrivate); + itkGetGlobalDeclarationMacro(ObjectFactoryBasePrivate, PimplGlobals); + OverRideMap *m_OverrideMap; /** Initialize the static list of Factories. */ @@ -257,11 +256,10 @@ class ITKCommon_EXPORT ObjectFactoryBase:public Object unsigned long m_LibraryDate; std::string m_LibraryPath; - static bool m_StrictVersionChecking; - - // This variable should NOT be accessed directly, but through GetObjectFactoryBase - static ObjectFactoryBasePrivate * m_ObjectFactoryBasePrivate; + static ObjectFactoryBasePrivate * m_PimplGlobals; }; + + } // end namespace itk #endif diff --git a/Modules/Core/Common/include/itkSingleton.h b/Modules/Core/Common/include/itkSingleton.h new file mode 100644 index 00000000000..3f9b71ff974 --- /dev/null +++ b/Modules/Core/Common/include/itkSingleton.h @@ -0,0 +1,115 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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 itkSingleton_h +#define itkSingleton_h + +#include "itkMacro.h" +#include "itkSingletonMacro.h" +#include +#include + +/** \brief A function which does nothing + * + * This function is to be used to mark parameters as unused to suppress + * compiler warning. It can be used when the parameter needs to be named + * (i.e. itkNotUsed cannot be used) but is not always used. It ensures + * that the parameter is not optimized out. + */ +template +inline void Unused( const T &) {}; + +namespace itk +{ +/** \class SingletonIndex + * \brief Implementation detail. + * + * \ingroup ITKCommon + */ + +class ITKCommon_EXPORT SingletonIndex +{ +public: + /** Standard class typedefs. */ + typedef SingletonIndex Self; + typedef std::map, std::function > > SingletonData; + + // obtain a global registered in the singleton index under the + // globalName, if unknown then nullptr will be returned. + template + T *GetGlobalInstance( const char *globalName ) + { return static_cast(this->GetGlobalInstancePrivate(globalName)); } + + + // returns true if the globalName has not been registered yet. + // + // It is assumed that the global will remain valid until the start + // of globals being destroyed. + template + bool SetGlobalInstance( const char * globalName, T * global, std::function func, std::function deleteFunc) + { return this->SetGlobalInstancePrivate(globalName, global, func, deleteFunc);} + + /** Set/Get the pointer to GlobalSingleton. + * Note that SetGlobalSingleton is not concurrent thread safe. */ + static Self* GetInstance(); + static void SetInstance(Self *SingletonIndex); + ~SingletonIndex(); + +private: + + // may return nullptr if string is not registered already + // + // access something like a std::map or + // registered globals, it may be possible to restrict the held + // classes to be derived from itk::LightObject, so dynamic cast can + // work, and could use some type of Holder class for intrinsic types + void * GetGlobalInstancePrivate( const char *globalName ); + // If globalName is already registered than false is return, + // otherwise global is added to the singleton index under globalName + bool SetGlobalInstancePrivate( const char * globalName, void * global, std::function func, std::function deleteFunc); + + /** The static GlobalSingleton. This is initialized to nullptr as the first + * stage of static initialization. It is then populated on the first call to + * itk::Singleton::Modified() but it can be overridden with SetGlobalSingleton(). + * */ + SingletonData m_GlobalObjects; + static Self* m_Instance; +// static SingletonIndexPrivate * m_GlobalSingleton; +}; + + +// A wrapper for a global variable registered in the singleton index. +template +T* Singleton(const char *globalName, std::function func, std::function deleteFunc) +{ + static SingletonIndex * singletonIndex = SingletonIndex::GetInstance(); + Unused(singletonIndex); + T* instance = SingletonIndex::GetInstance()->GetGlobalInstance(globalName); + if( instance == nullptr ) + { + instance = new T; + if (!SingletonIndex::GetInstance()->SetGlobalInstance(globalName, instance, func, deleteFunc)) + { + delete instance; + instance = nullptr; + } + } + return instance; +} +} // end namespace itk + +#endif diff --git a/Modules/Core/Common/include/itkSingletonMacro.h b/Modules/Core/Common/include/itkSingletonMacro.h new file mode 100644 index 00000000000..9ccb30ebca0 --- /dev/null +++ b/Modules/Core/Common/include/itkSingletonMacro.h @@ -0,0 +1,68 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +/** + * itkSingletonMacro.h defines macros that are used to declare and define + * global variables across ITK with a global map that is used to synchronize + * this variables across multiple instantiations of ITK if necessary. + * Note: this is rarely necessary. + */ + +#ifndef itkSingletonMacro_h +#define itkSingletonMacro_h + +#define itkInitGlobalsMacro(VarName) \ + { \ + static auto * staticGlobals = Get##VarName##Pointer (); \ + (void) staticGlobals; \ + } + +#define itkGetGlobalDeclarationMacro(Type, VarName) \ +static Type * Get##VarName##Pointer(); + +#define itkGetGlobalSimpleMacro(Class, Type, Name) \ + itkGetGlobalInitializeMacro(Class, Type, Name, Class, (void)0) + +#define itkGetGlobalValueMacro(Class, Type, Name, Value) \ + itkGetGlobalInitializeMacro(Class, Type, Name, Name, *m_##Name = Value) + +#define itkGetGlobalInitializeMacro(Class, Type, VarName, SingletonName, Init) \ +Type * Class::Get##VarName##Pointer() \ +{ \ + if( m_##VarName == nullptr ) \ + { \ + static auto setLambda = [](void * a) \ + { \ + delete m_##VarName; \ + m_##VarName = static_cast(a); \ + }; \ + static auto deleteLambda = []() \ + { \ + delete m_##VarName; \ + m_##VarName = nullptr; \ + }; \ + auto* old_instance = SingletonIndex::GetInstance()->GetGlobalInstance(#SingletonName); \ + m_##VarName = Singleton( #SingletonName , setLambda, deleteLambda); \ + if( old_instance == nullptr) \ + { \ + Init; \ + }\ + } \ + return m_##VarName; \ +} + +#endif diff --git a/Modules/Core/Common/include/itkThreadPool.h b/Modules/Core/Common/include/itkThreadPool.h index 378eebd5147..f9460eeedad 100644 --- a/Modules/Core/Common/include/itkThreadPool.h +++ b/Modules/Core/Common/include/itkThreadPool.h @@ -29,6 +29,8 @@ #include "itkObject.h" #include "itkObjectFactory.h" +#include "itkSingletonMacro.h" + namespace itk { @@ -113,11 +115,6 @@ class ITKCommon_EXPORT ThreadPool : public Object static bool GetDoNotWaitForThreads(); static void SetDoNotWaitForThreads(bool doNotWaitForThreads); - /** Set/Get the pointer to ThreadPoolGlobals. - * Note that SetThreadPoolGlobals is not concurrent thread safe. */ - static ThreadPoolGlobals * GetThreadPoolGlobals(); - static void SetThreadPoolGlobals(::itk::ThreadPoolGlobals * globals); - protected: /* We need access to the mutex in AddWork, and the variable is only @@ -129,6 +126,9 @@ class ITKCommon_EXPORT ThreadPool : public Object private: + /** Only used to synchronize the global variable across static libraries.*/ + itkGetGlobalDeclarationMacro(ThreadPoolGlobals, PimplGlobals); + /** This is a list of jobs submitted to the thread pool. * This is the only place where the jobs are submitted. * Filled by AddWork, emptied by ThreadExecute. */ @@ -146,7 +146,7 @@ class ITKCommon_EXPORT ThreadPool : public Object bool m_Stopping{ false }; /** To lock on the internal variables */ - static ThreadPoolGlobals * m_ThreadPoolGlobals; + static ThreadPoolGlobals * m_PimplGlobals; /** The continuously running thread function */ static void ThreadExecute(); diff --git a/Modules/Core/Common/include/itkTimeStamp.h b/Modules/Core/Common/include/itkTimeStamp.h index ee130c97e5b..4bdbcb1c91f 100644 --- a/Modules/Core/Common/include/itkTimeStamp.h +++ b/Modules/Core/Common/include/itkTimeStamp.h @@ -31,6 +31,7 @@ #include "itkMacro.h" #include "itkIntTypes.h" #include +#include "itkSingletonMacro.h" namespace itk { @@ -108,19 +109,18 @@ class ITKCommon_EXPORT TimeStamp * another. */ Self & operator=( const Self & other ) = default; +private: /** Set/Get the pointer to GlobalTimeStamp. * Note that SetGlobalTimeStamp is not concurrent thread safe. */ - static GlobalTimeStampType * GetGlobalTimeStamp(); - static void SetGlobalTimeStamp( GlobalTimeStampType * timeStamp ); + itkGetGlobalDeclarationMacro(GlobalTimeStampType, GlobalTimeStamp); -private: ModifiedTimeType m_ModifiedTime; /** The static GlobalTimeStamp. This is initialized to NULL as the first * stage of static initialization. It is then populated on the first call to * itk::TimeStamp::Modified() but it can be overridden with SetGlobalTimeStamp(). * */ - static GlobalTimeStampType * m_GlobalTimeStamp; + static GlobalTimeStampType *m_GlobalTimeStamp; }; } // end namespace itk diff --git a/Modules/Core/Common/src/CMakeLists.txt b/Modules/Core/Common/src/CMakeLists.txt index 5d569dab057..50028979959 100644 --- a/Modules/Core/Common/src/CMakeLists.txt +++ b/Modules/Core/Common/src/CMakeLists.txt @@ -120,6 +120,7 @@ set(ITKCommon_SRCS itkTimeProbe.cxx itkNumericTraitsRGBPixel.cxx itkTimeStamp.cxx + itkSingleton.cxx itkTetrahedronCellTopology.cxx itkThreadedIndexedContainerPartitioner.cxx itkObjectFactoryBase.cxx @@ -141,7 +142,6 @@ set(ITKCommon_SRCS if(WIN32) list(APPEND ITKCommon_SRCS itkWin32OutputWindow.cxx) endif() - if(ITK_USE_WIN32_THREADS OR ITK_USE_PTHREADS) list(APPEND ITKCommon_SRCS itkPoolMultiThreader.cxx itkThreadPool.cxx) endif() diff --git a/Modules/Core/Common/src/itkBuildInformation.cxx.in b/Modules/Core/Common/src/itkBuildInformation.cxx.in index 58c2ed8a4a4..98c4cd97703 100644 --- a/Modules/Core/Common/src/itkBuildInformation.cxx.in +++ b/Modules/Core/Common/src/itkBuildInformation.cxx.in @@ -18,13 +18,14 @@ #include "itkBuildInformation.h" #include "itkObjectFactory.h" +#include "itkSingleton.h" #include // Construct const versions via the emplace method. This macro simplifies the text // written in ITK/Modules/Core/Common/src/CMakeLists.txt. #define MAKE_MAP_ENTRY(KEY, VALUE, DESCRIPTION ) \ -m_Map.emplace( \ +m_PimplGlobals->m_Map.emplace( \ std::pair< MapKeyType, InformationValueType>( \ MapKeyType{ KEY }, \ InformationValueType{ MapValueType{ VALUE }, MapValueDescriptionType{ DESCRIPTION } } \ @@ -33,9 +34,19 @@ m_Map.emplace( namespace itk { -std::mutex BuildInformation::m_Mutex; -BuildInformation::Pointer BuildInformation::m_InformationInstance; -BuildInformation::MapType BuildInformation::m_Map; +struct BuildInformationGlobals +{ + BuildInformationGlobals():m_InformationInstance(nullptr) + {} +/** To lock on the internal variables */ + std::mutex m_Mutex; + BuildInformation::Pointer m_InformationInstance; + BuildInformation::MapType m_Map; +}; + +itkGetGlobalSimpleMacro(BuildInformation, BuildInformationGlobals, PimplGlobals); + +BuildInformationGlobals * BuildInformation::m_PimplGlobals; BuildInformation::Pointer BuildInformation @@ -48,21 +59,22 @@ BuildInformation::Pointer BuildInformation ::GetInstance() { - std::lock_guard mutexHolder(m_Mutex); - if (m_InformationInstance.IsNull()) + itkInitGlobalsMacro(PimplGlobals); + std::lock_guard mutexHolder(m_PimplGlobals->m_Mutex); + if (m_PimplGlobals->m_InformationInstance.IsNull()) { - m_InformationInstance = ObjectFactory::Create(); + m_PimplGlobals->m_InformationInstance = ObjectFactory::Create(); { new BuildInformation(); //constructor sets m_InformationInstance } } - return m_InformationInstance; + return m_PimplGlobals->m_InformationInstance; } const BuildInformation::MapType & BuildInformation::GetMap() { - return BuildInformation::GetInstance()->m_Map; + return BuildInformation::GetInstance()->m_PimplGlobals->m_Map; } const BuildInformation::MapValueType @@ -96,7 +108,7 @@ BuildInformation::GetAllKeys() { std::vector< BuildInformation::MapKeyType > keyVector; keyVector.reserve(30); - for( auto elem : BuildInformation::GetInstance()->m_Map ) + for( auto elem : BuildInformation::GetInstance()->m_PimplGlobals->m_Map ) { keyVector.emplace_back( elem.first ); } @@ -106,8 +118,8 @@ BuildInformation::GetAllKeys() BuildInformation ::BuildInformation() { - m_InformationInstance = this; //threads need this - m_InformationInstance->UnRegister(); // Remove extra reference + m_PimplGlobals->m_InformationInstance = this; //threads need this + m_PimplGlobals->m_InformationInstance->UnRegister(); // Remove extra reference @MAPPING_VALUES@ } diff --git a/Modules/Core/Common/src/itkDataObject.cxx b/Modules/Core/Common/src/itkDataObject.cxx index f2cf8c811bd..a0136514bfd 100644 --- a/Modules/Core/Common/src/itkDataObject.cxx +++ b/Modules/Core/Common/src/itkDataObject.cxx @@ -26,11 +26,14 @@ * *=========================================================================*/ #include "itkProcessObject.h" +#include "itkSingleton.h" namespace itk { + +itkGetGlobalValueMacro(DataObject, bool, GlobalReleaseDataFlag, false); // after use by filter -bool DataObject:: m_GlobalReleaseDataFlag = false; +bool * DataObject::m_GlobalReleaseDataFlag; DataObjectError ::DataObjectError() noexcept: @@ -152,11 +155,12 @@ void DataObject ::SetGlobalReleaseDataFlag(bool val) { - if ( val == m_GlobalReleaseDataFlag ) + itkInitGlobalsMacro(GlobalReleaseDataFlag); + if ( val == *m_GlobalReleaseDataFlag ) { return; } - m_GlobalReleaseDataFlag = val; + *m_GlobalReleaseDataFlag = val; } //---------------------------------------------------------------------------- @@ -164,7 +168,7 @@ bool DataObject ::GetGlobalReleaseDataFlag() { - return m_GlobalReleaseDataFlag; + return *DataObject::GetGlobalReleaseDataFlagPointer(); } //---------------------------------------------------------------------------- diff --git a/Modules/Core/Common/src/itkFloatingPointExceptions.cxx b/Modules/Core/Common/src/itkFloatingPointExceptions.cxx index 63cd317ae67..ddd6e1e7b98 100644 --- a/Modules/Core/Common/src/itkFloatingPointExceptions.cxx +++ b/Modules/Core/Common/src/itkFloatingPointExceptions.cxx @@ -17,6 +17,7 @@ *=========================================================================*/ #include "itkFloatingPointExceptions.h" #include +#include "itkSingleton.h" // // invariant over all targets -- set a preference for what @@ -31,35 +32,43 @@ namespace itk { -FloatingPointExceptions::ExceptionAction -FloatingPointExceptions::m_ExceptionAction = - FloatingPointExceptions::ABORT; -bool FloatingPointExceptions::m_Enabled(false); +struct ExceptionGlobals +{ + ExceptionGlobals():m_ExceptionAction(FloatingPointExceptions::ABORT), + m_Enabled(false) + {}; + FloatingPointExceptions::ExceptionAction m_ExceptionAction; + bool m_Enabled; +}; void FloatingPointExceptions ::SetExceptionAction(ExceptionAction a) { - FloatingPointExceptions::m_ExceptionAction = a; + itkInitGlobalsMacro(PimplGlobals); + FloatingPointExceptions::m_PimplGlobals->m_ExceptionAction = a; } FloatingPointExceptions::ExceptionAction FloatingPointExceptions::GetExceptionAction() { - return FloatingPointExceptions::m_ExceptionAction; + itkInitGlobalsMacro(PimplGlobals); + return FloatingPointExceptions::m_PimplGlobals->m_ExceptionAction; } bool FloatingPointExceptions:: GetEnabled() { - return FloatingPointExceptions::m_Enabled; + itkInitGlobalsMacro(PimplGlobals); + return FloatingPointExceptions::m_PimplGlobals->m_Enabled; } void FloatingPointExceptions:: SetEnabled(bool val) { + itkInitGlobalsMacro(PimplGlobals); if(val) { FloatingPointExceptions::Enable(); @@ -70,6 +79,10 @@ SetEnabled(bool val) } } +itkGetGlobalSimpleMacro(FloatingPointExceptions, ExceptionGlobals, PimplGlobals); + +ExceptionGlobals * FloatingPointExceptions::m_PimplGlobals; + } // end of itk namespace namespace { diff --git a/Modules/Core/Common/src/itkFloatingPointExceptions_unix.cxx b/Modules/Core/Common/src/itkFloatingPointExceptions_unix.cxx index 2f5e49b2208..0c4f391db5e 100644 --- a/Modules/Core/Common/src/itkFloatingPointExceptions_unix.cxx +++ b/Modules/Core/Common/src/itkFloatingPointExceptions_unix.cxx @@ -135,6 +135,7 @@ void FloatingPointExceptions ::Enable() { + itkInitGlobalsMacro(PimplGlobals); #if defined(ITK_HAS_FPE_CAPABILITY) itk_feenableexcept (FE_DIVBYZERO); itk_feenableexcept (FE_INVALID); @@ -146,7 +147,7 @@ ::Enable() act.sa_flags = SA_SIGINFO; sigaction(SIGFPE,&act,nullptr); #endif - FloatingPointExceptions::m_Enabled = true; + FloatingPointExceptions::m_PimplGlobals->m_Enabled = true; (void)itkFloatingPointExceptionsNotSupported; // avoid unused-function warning #else itkFloatingPointExceptionsNotSupported(); @@ -157,10 +158,11 @@ void FloatingPointExceptions ::Disable() { + itkInitGlobalsMacro(PimplGlobals); #if defined(ITK_HAS_FPE_CAPABILITY) itk_fedisableexcept (FE_DIVBYZERO); itk_fedisableexcept (FE_INVALID); - FloatingPointExceptions::m_Enabled = false; + FloatingPointExceptions::m_PimplGlobals->m_Enabled = false; #else itkFloatingPointExceptionsNotSupported(); #endif @@ -169,6 +171,7 @@ ::Disable() bool FloatingPointExceptions ::HasFloatingPointExceptionsSupport() { + itkInitGlobalsMacro(PimplGlobals); #if defined(ITK_HAS_FPE_CAPABILITY) return true; #else diff --git a/Modules/Core/Common/src/itkFloatingPointExceptions_win.cxx b/Modules/Core/Common/src/itkFloatingPointExceptions_win.cxx index ea3debf02b8..32a0334edf9 100644 --- a/Modules/Core/Common/src/itkFloatingPointExceptions_win.cxx +++ b/Modules/Core/Common/src/itkFloatingPointExceptions_win.cxx @@ -32,23 +32,26 @@ namespace itk void FloatingPointExceptions ::Enable() { + itkInitGlobalsMacro(PimplGlobals); // enable floating point exceptions on MSVC _controlfp(_EM_DENORMAL | _EM_UNDERFLOW | _EM_INEXACT, _MCW_EM); - FloatingPointExceptions::m_Enabled = true; + FloatingPointExceptions::m_PimplGlobals->m_Enabled = true; } void FloatingPointExceptions ::Disable() { + itkInitGlobalsMacro(PimplGlobals); // disable floating point exceptions on MSVC _controlfp(_EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW | _EM_INEXACT, _MCW_EM); - FloatingPointExceptions::m_Enabled = false; + FloatingPointExceptions::m_PimplGlobals->m_Enabled = false; } bool FloatingPointExceptions ::HasFloatingPointExceptionsSupport() { + itkInitGlobalsMacro(PimplGlobals); return true; } @@ -59,18 +62,21 @@ ::HasFloatingPointExceptionsSupport() void FloatingPointExceptions ::Enable() { + itkInitGlobalsMacro(PimplGlobals); itkFloatingPointExceptionsNotSupported(); } void FloatingPointExceptions ::Disable() { + itkInitGlobalsMacro(PimplGlobals); itkFloatingPointExceptionsNotSupported(); } bool FloatingPointExceptions ::HasFloatingPointExceptionsSupport() { + itkInitGlobalsMacro(PimplGlobals); return false; } diff --git a/Modules/Core/Common/src/itkMersenneTwisterRandomVariateGenerator.cxx b/Modules/Core/Common/src/itkMersenneTwisterRandomVariateGenerator.cxx index d4000a89c0f..d63509ea428 100644 --- a/Modules/Core/Common/src/itkMersenneTwisterRandomVariateGenerator.cxx +++ b/Modules/Core/Common/src/itkMersenneTwisterRandomVariateGenerator.cxx @@ -17,16 +17,28 @@ *=========================================================================*/ #include "itkMersenneTwisterRandomVariateGenerator.h" +#include "itkSingleton.h" + namespace itk { namespace Statistics { -// Static/Global variables -MersenneTwisterRandomVariateGenerator::Pointer MersenneTwisterRandomVariateGenerator::m_StaticInstance = nullptr; -std::recursive_mutex MersenneTwisterRandomVariateGenerator::m_StaticInstanceLock; -MersenneTwisterRandomVariateGenerator::IntegerType MersenneTwisterRandomVariateGenerator::m_StaticDiffer = 0; +/** Private nested class to easily synchronize global variables across static libraries.*/ +struct MersenneTwisterGlobals +{ + MersenneTwisterGlobals():m_StaticInstance(nullptr), + m_StaticDiffer(0) + {}; + MersenneTwisterRandomVariateGenerator::Pointer m_StaticInstance; + std::recursive_mutex m_StaticInstanceLock; + MersenneTwisterRandomVariateGenerator::IntegerType m_StaticDiffer; +}; + +itkGetGlobalSimpleMacro(MersenneTwisterRandomVariateGenerator, MersenneTwisterGlobals, PimplGlobals); + +MersenneTwisterGlobals * MersenneTwisterRandomVariateGenerator::m_PimplGlobals; MersenneTwisterRandomVariateGenerator::Pointer MersenneTwisterRandomVariateGenerator @@ -61,15 +73,16 @@ MersenneTwisterRandomVariateGenerator::Pointer MersenneTwisterRandomVariateGenerator ::GetInstance() { - std::lock_guard< std::recursive_mutex > mutexHolder( m_StaticInstanceLock ); + itkInitGlobalsMacro(PimplGlobals); + std::lock_guard< std::recursive_mutex > mutexHolder( m_PimplGlobals->m_StaticInstanceLock ); - if ( !m_StaticInstance ) + if ( !m_PimplGlobals->m_StaticInstance ) { - m_StaticInstance = MersenneTwisterRandomVariateGenerator::CreateInstance(); - m_StaticInstance->SetSeed(); + m_PimplGlobals->m_StaticInstance = MersenneTwisterRandomVariateGenerator::CreateInstance(); + m_PimplGlobals->m_StaticInstance->SetSeed(); } - return m_StaticInstance; + return m_PimplGlobals->m_StaticInstance; } MersenneTwisterRandomVariateGenerator @@ -85,6 +98,7 @@ MersenneTwisterRandomVariateGenerator::IntegerType MersenneTwisterRandomVariateGenerator ::hash(time_t t, clock_t c) { + itkInitGlobalsMacro(PimplGlobals); // Get an IntegerType from t and c // Better than IntegerType(x) in case x is floating point in [0,1] // Based on code by Lawrence Kirby: fred at genesis dot demon dot co dot uk @@ -108,18 +122,19 @@ ::hash(time_t t, clock_t c) h2 += p[j]; } // lock for m_StaticDiffer - std::lock_guard< std::recursive_mutex > mutexHolder( m_StaticInstanceLock ); - return ( h1 + m_StaticDiffer++ ) ^ h2; + std::lock_guard< std::recursive_mutex > mutexHolder( m_PimplGlobals->m_StaticInstanceLock ); + return ( h1 + m_PimplGlobals->m_StaticDiffer++ ) ^ h2; } MersenneTwisterRandomVariateGenerator::IntegerType MersenneTwisterRandomVariateGenerator ::GetNextSeed() { + itkInitGlobalsMacro(PimplGlobals); IntegerType newSeed = GetInstance()->GetSeed(); { - std::lock_guard< std::recursive_mutex > mutexHolder( m_StaticInstanceLock ); - newSeed += m_StaticDiffer++; + std::lock_guard< std::recursive_mutex > mutexHolder( m_PimplGlobals->m_StaticInstanceLock ); + newSeed += m_PimplGlobals->m_StaticDiffer++; } return newSeed; } diff --git a/Modules/Core/Common/src/itkMultiThreaderBase.cxx b/Modules/Core/Common/src/itkMultiThreaderBase.cxx index 9badf0b6be9..cf08b1d199b 100644 --- a/Modules/Core/Common/src/itkMultiThreaderBase.cxx +++ b/Modules/Core/Common/src/itkMultiThreaderBase.cxx @@ -37,6 +37,7 @@ #include "itksys/SystemTools.hxx" #include "itksys/SystemInformation.hxx" #include "itkImageSourceCommon.h" +#include "itkSingleton.h" #include "itkProcessObject.h" #include #include @@ -47,143 +48,58 @@ #include "itkTBBMultiThreader.h" #endif - namespace itk { - struct MultiThreaderBaseGlobals - { - // Initialize static members. - MultiThreaderBaseGlobals() - {}; - // GlobalDefaultThreaderTypeIsInitialized is used only in this - // file to ensure that the ITK_GLOBAL_DEFAULT_THREADER or - // ITK_USE_THREADPOOL environmenal variables are - // only used as a fall back option. If the SetGlobalDefaultThreaderType - // API is ever used by the developer, the developers choice is - // respected over the environmental variable. - bool GlobalDefaultThreaderTypeIsInitialized{false}; - std::mutex globalDefaultInitializerLock; +struct MultiThreaderBaseGlobals +{ + // Initialize static members. + MultiThreaderBaseGlobals():GlobalDefaultThreaderTypeIsInitialized(false), // Global value to control weather the threadpool implementation should // be used. This defaults to the environmental variable // ITK_GLOBAL_DEFAULT_THREADER. If that is not present, then // ITK_USE_THREADPOOL is examined. - MultiThreaderBase::ThreaderType m_GlobalDefaultThreader{ #if defined(ITK_USE_TBB) - MultiThreaderBase::ThreaderType::TBB + m_GlobalDefaultThreader(MultiThreaderBase::ThreaderType::TBB), #elif defined(POOL_MULTI_THREADER_AVAILABLE) - MultiThreaderBase::ThreaderType::Pool + m_GlobalDefaultThreader(MultiThreaderBase::ThreaderType::Pool), #else - MultiThreaderBase::ThreaderType::Platform + m_GlobalDefaultThreader(MultiThreaderBase::ThreaderType::Platform), #endif + m_GlobalMaximumNumberOfThreads(ITK_MAX_THREADS), + // Global default number of threads : 0 => Not initialized. + m_GlobalDefaultNumberOfThreads(0) + {}; + // GlobalDefaultThreaderTypeIsInitialized is used only in this + // file to ensure that the ITK_GLOBAL_DEFAULT_THREADER or + // ITK_USE_THREADPOOL environmenal variables are + // only used as a fall back option. If the SetGlobalDefaultThreaderType + // API is ever used by the developer, the developers choice is + // respected over the environmental variable. + bool GlobalDefaultThreaderTypeIsInitialized; + std::mutex globalDefaultInitializerLock; + + // Global value to control weather the threadpool implementation should + // be used. This defaults to the environmental variable + // ITK_GLOBAL_DEFAULT_THREADER. If that is not present, then + // ITK_USE_THREADPOOL is examined. + MultiThreaderBase::ThreaderType m_GlobalDefaultThreader; + + // Global variable defining the maximum number of threads that can be used. + // The m_GlobalMaximumNumberOfThreads must always be less than or equal to + // ITK_MAX_THREADS and greater than zero. */ + ThreadIdType m_GlobalMaximumNumberOfThreads; + + // Global variable defining the default number of threads to set at + // construction time of a MultiThreaderBase instance. The + // m_GlobalDefaultNumberOfThreads must always be less than or equal to the + // m_GlobalMaximumNumberOfThreads and larger or equal to 1 once it has been + // initialized in the constructor of the first MultiThreaderBase instantiation. + ThreadIdType m_GlobalDefaultNumberOfThreads; }; - // Global variable defining the maximum number of threads that can be used. - // The m_GlobalMaximumNumberOfThreads must always be less than or equal to - // ITK_MAX_THREADS and greater than zero. */ - ThreadIdType m_GlobalMaximumNumberOfThreads{ITK_MAX_THREADS}; - - // Global variable defining the default number of threads to set at - // construction time of a MultiThreaderBase instance. The - // m_GlobalDefaultNumberOfThreads must always be less than or equal to the - // m_GlobalMaximumNumberOfThreads and larger or equal to 1 once it has been - // initialized in the constructor of the first MultiThreaderBase instantiation. - // Global default number of threads : 0 => Not initialized. - ThreadIdType m_GlobalDefaultNumberOfThreads{0}; - }; -}//end of itk namespace - -namespace -{ -static std::mutex globalInitializerLock; - -/** \brief A function which does nothing - * - * This function is to be used to mark parameters as unused to suppress - * compiler warning. It can be used when the parameter needs to be named - * (i.e. itkNotUsed cannot be used) but is not always used. It ensures - * that the parameter is not optimized out. - */ -template -void Unused( const T &) {}; - -// This ensures that m_MultiThreaderBaseGlobals is has been initialized once the library -// has been loaded. In some cases, this call will perform the initialization. -// In other cases, static initializers like the IO factory initialization code -// will have done the initialization. -static ::itk::MultiThreaderBaseGlobals * initializedMultiThreaderBaseGlobals = ::itk::MultiThreaderBase::GetMultiThreaderBaseGlobals(); - -/** \class MultiThreaderBaseGlobalsInitializer - * - * \brief Initialize a MultiThreaderBaseGlobals and delete it on program - * completion. - * */ -class MultiThreaderBaseGlobalsInitializer -{ -public: - using Self = MultiThreaderBaseGlobalsInitializer; - - MultiThreaderBaseGlobalsInitializer() = default; - - /** Delete the time stamp if it was created. */ - ~MultiThreaderBaseGlobalsInitializer() - { - delete m_MultiThreaderBaseGlobals; - m_MultiThreaderBaseGlobals = nullptr; - } - - /** Create the MultiThreaderBaseGlobals if needed and return it. */ - static ::itk::MultiThreaderBaseGlobals * GetMultiThreaderBaseGlobals() - { - if( !m_MultiThreaderBaseGlobals ) - { - // GetGlobalDefaultThreaderType() must be thread safe and can potentially call - // this method, even though it is very unlikely. - std::lock_guard< std::mutex > lock(globalInitializerLock); - if( !m_MultiThreaderBaseGlobals ) - { - m_MultiThreaderBaseGlobals = new ::itk::MultiThreaderBaseGlobals; - // To avoid being optimized out. The compiler does not like this - // statement at a higher scope. - Unused(initializedMultiThreaderBaseGlobals); - } - } - return m_MultiThreaderBaseGlobals; - } - -private: - static ::itk::MultiThreaderBaseGlobals * m_MultiThreaderBaseGlobals; -}; - -// Takes care of cleaning up the MultiThreaderBaseGlobals -static MultiThreaderBaseGlobalsInitializer MultiThreaderBaseGlobalsInitializerInstance; -// Initialized by the compiler to zero -::itk::MultiThreaderBaseGlobals * MultiThreaderBaseGlobalsInitializer::m_MultiThreaderBaseGlobals; +itkGetGlobalSimpleMacro(MultiThreaderBase, MultiThreaderBaseGlobals, PimplGlobals); -} // end anonymous namespace - - -namespace itk -{ - -::itk::MultiThreaderBaseGlobals * -MultiThreaderBase -::GetMultiThreaderBaseGlobals() -{ - if( m_MultiThreaderBaseGlobals == nullptr ) - { - m_MultiThreaderBaseGlobals = MultiThreaderBaseGlobalsInitializer::GetMultiThreaderBaseGlobals(); - } - return m_MultiThreaderBaseGlobals; -} - - -void -MultiThreaderBase -::SetMultiThreaderBaseGlobals( MultiThreaderBaseGlobals * multiThreaderBaseGlobals ) -{ - m_MultiThreaderBaseGlobals = multiThreaderBaseGlobals; -} #if ! defined (ITK_LEGACY_REMOVE) void MultiThreaderBase::SetGlobalDefaultUseThreadPool( const bool GlobalDefaultUseThreadPool ) @@ -206,12 +122,10 @@ bool MultiThreaderBase::GetGlobalDefaultUseThreadPool( ) void MultiThreaderBase::SetGlobalDefaultThreader(ThreaderType threaderType) { - // This is called once, on-demand to ensure that m_MultiThreaderBaseGlobals is - // initialized. - static MultiThreaderBaseGlobals * multiThreaderBaseGlobals = GetMultiThreaderBaseGlobals(); - Unused(multiThreaderBaseGlobals); - m_MultiThreaderBaseGlobals->m_GlobalDefaultThreader = threaderType; - m_MultiThreaderBaseGlobals->GlobalDefaultThreaderTypeIsInitialized = true; + itkInitGlobalsMacro(PimplGlobals); + + m_PimplGlobals->m_GlobalDefaultThreader = threaderType; + m_PimplGlobals->GlobalDefaultThreaderTypeIsInitialized = true; } MultiThreaderBase::ThreaderType @@ -219,19 +133,15 @@ MultiThreaderBase ::GetGlobalDefaultThreader() { // This method must be concurrent thread safe + itkInitGlobalsMacro(PimplGlobals); - // This is called once, on-demand to ensure that m_MultiThreaderBaseGlobals is - // initialized. - static MultiThreaderBaseGlobals * multiThreaderBaseGlobals = GetMultiThreaderBaseGlobals(); - Unused(multiThreaderBaseGlobals); - - if( !m_MultiThreaderBaseGlobals->GlobalDefaultThreaderTypeIsInitialized ) + if( !m_PimplGlobals->GlobalDefaultThreaderTypeIsInitialized ) { - std::lock_guard< std::mutex > lock(m_MultiThreaderBaseGlobals->globalDefaultInitializerLock); + std::lock_guard< std::mutex > lock(m_PimplGlobals->globalDefaultInitializerLock); // After we have the lock, double check the initialization // flag to ensure it hasn't been changed by another thread. - if (!m_MultiThreaderBaseGlobals->GlobalDefaultThreaderTypeIsInitialized ) + if (!m_PimplGlobals->GlobalDefaultThreaderTypeIsInitialized ) { std::string envVar; // first check ITK_GLOBAL_DEFAULT_THREADER @@ -245,7 +155,7 @@ ::GetGlobalDefaultThreader() } } // if that was not set check ITK_USE_THREADPOOL (deprecated) - else if( !m_MultiThreaderBaseGlobals->GlobalDefaultThreaderTypeIsInitialized + else if( !m_PimplGlobals->GlobalDefaultThreaderTypeIsInitialized && itksys::SystemTools::GetEnv("ITK_USE_THREADPOOL",envVar) ) { envVar = itksys::SystemTools::UpperCase(envVar); @@ -268,10 +178,10 @@ You should now use ITK_GLOBAL_DEFAULT_THREADER\ } // always set that we are initialized - m_MultiThreaderBaseGlobals->GlobalDefaultThreaderTypeIsInitialized=true; + m_PimplGlobals->GlobalDefaultThreaderTypeIsInitialized=true; } } - return m_MultiThreaderBaseGlobals->m_GlobalDefaultThreader; + return m_PimplGlobals->m_GlobalDefaultThreader; } MultiThreaderBase::ThreaderType @@ -299,51 +209,42 @@ ::ThreaderTypeFromString(std::string threaderString) void MultiThreaderBase::SetGlobalMaximumNumberOfThreads(ThreadIdType val) { - // This is called once, on-demand to ensure that m_MultiThreaderBaseGlobals is - // initialized. - static MultiThreaderBaseGlobals * multiThreaderBaseGlobals = GetMultiThreaderBaseGlobals(); - Unused(multiThreaderBaseGlobals); + itkInitGlobalsMacro(PimplGlobals); - m_MultiThreaderBaseGlobals->m_GlobalMaximumNumberOfThreads = val; + m_PimplGlobals->m_GlobalMaximumNumberOfThreads = val; // clamp between 1 and ITK_MAX_THREADS - m_MultiThreaderBaseGlobals->m_GlobalMaximumNumberOfThreads = - std::min( m_MultiThreaderBaseGlobals->m_GlobalMaximumNumberOfThreads, + m_PimplGlobals->m_GlobalMaximumNumberOfThreads = + std::min( m_PimplGlobals->m_GlobalMaximumNumberOfThreads, (ThreadIdType) ITK_MAX_THREADS ); - m_MultiThreaderBaseGlobals->m_GlobalMaximumNumberOfThreads = - std::max( m_MultiThreaderBaseGlobals->m_GlobalMaximumNumberOfThreads, + m_PimplGlobals->m_GlobalMaximumNumberOfThreads = + std::max( m_PimplGlobals->m_GlobalMaximumNumberOfThreads, NumericTraits::OneValue() ); // If necessary reset the default to be used from now on. - m_MultiThreaderBaseGlobals->m_GlobalDefaultNumberOfThreads = - std::min( m_MultiThreaderBaseGlobals->m_GlobalDefaultNumberOfThreads, - m_MultiThreaderBaseGlobals->m_GlobalMaximumNumberOfThreads); + m_PimplGlobals->m_GlobalDefaultNumberOfThreads = + std::min( m_PimplGlobals->m_GlobalDefaultNumberOfThreads, + m_PimplGlobals->m_GlobalMaximumNumberOfThreads); } ThreadIdType MultiThreaderBase::GetGlobalMaximumNumberOfThreads() { - // This is called once, on-demand to ensure that m_MultiThreaderBaseGlobals is - // initialized. - static MultiThreaderBaseGlobals * multiThreaderBaseGlobals = GetMultiThreaderBaseGlobals(); - Unused(multiThreaderBaseGlobals); - return m_MultiThreaderBaseGlobals->m_GlobalMaximumNumberOfThreads; + itkInitGlobalsMacro(PimplGlobals); + return m_PimplGlobals->m_GlobalMaximumNumberOfThreads; } void MultiThreaderBase::SetGlobalDefaultNumberOfThreads(ThreadIdType val) { - // This is called once, on-demand to ensure that m_MultiThreaderBaseGlobals is - // initialized. - static MultiThreaderBaseGlobals * multiThreaderBaseGlobals = GetMultiThreaderBaseGlobals(); - Unused(multiThreaderBaseGlobals); + itkInitGlobalsMacro(PimplGlobals); - m_MultiThreaderBaseGlobals->m_GlobalDefaultNumberOfThreads = val; + m_PimplGlobals->m_GlobalDefaultNumberOfThreads = val; - // clamp between 1 and m_MultiThreaderBaseGlobals->m_GlobalMaximumNumberOfThreads - m_MultiThreaderBaseGlobals->m_GlobalDefaultNumberOfThreads = - std::min( m_MultiThreaderBaseGlobals->m_GlobalDefaultNumberOfThreads, - m_MultiThreaderBaseGlobals->m_GlobalMaximumNumberOfThreads ); - m_MultiThreaderBaseGlobals->m_GlobalDefaultNumberOfThreads = - std::max( m_MultiThreaderBaseGlobals->m_GlobalDefaultNumberOfThreads, + // clamp between 1 and m_PimplGlobals->m_GlobalMaximumNumberOfThreads + m_PimplGlobals->m_GlobalDefaultNumberOfThreads = + std::min( m_PimplGlobals->m_GlobalDefaultNumberOfThreads, + m_PimplGlobals->m_GlobalMaximumNumberOfThreads ); + m_PimplGlobals->m_GlobalDefaultNumberOfThreads = + std::max( m_PimplGlobals->m_GlobalDefaultNumberOfThreads, NumericTraits::OneValue() ); } @@ -351,7 +252,7 @@ void MultiThreaderBase::SetGlobalDefaultNumberOfThreads(ThreadIdType val) void MultiThreaderBase::SetMaximumNumberOfThreads( ThreadIdType numberOfThreads ) { if( m_MaximumNumberOfThreads == numberOfThreads && - numberOfThreads <= m_MultiThreaderBaseGlobals->m_GlobalMaximumNumberOfThreads ) + numberOfThreads <= m_PimplGlobals->m_GlobalMaximumNumberOfThreads ) { return; } @@ -359,14 +260,14 @@ void MultiThreaderBase::SetMaximumNumberOfThreads( ThreadIdType numberOfThreads m_MaximumNumberOfThreads = numberOfThreads; // clamp between 1 and m_MultiThreaderBaseGlobals->m_GlobalMaximumNumberOfThreads - m_MaximumNumberOfThreads = std::min( m_MaximumNumberOfThreads, m_MultiThreaderBaseGlobals->m_GlobalMaximumNumberOfThreads ); + m_MaximumNumberOfThreads = std::min( m_MaximumNumberOfThreads, m_PimplGlobals->m_GlobalMaximumNumberOfThreads ); m_MaximumNumberOfThreads = std::max( m_MaximumNumberOfThreads, NumericTraits< ThreadIdType >::OneValue() ); } void MultiThreaderBase::SetNumberOfWorkUnits(ThreadIdType numberOfWorkUnits) { if( m_NumberOfWorkUnits == numberOfWorkUnits && - numberOfWorkUnits <= m_MultiThreaderBaseGlobals->m_GlobalMaximumNumberOfThreads ) + numberOfWorkUnits <= m_PimplGlobals->m_GlobalMaximumNumberOfThreads ) { return; } @@ -375,20 +276,15 @@ void MultiThreaderBase::SetNumberOfWorkUnits(ThreadIdType numberOfWorkUnits) // clamp between 1 and m_MultiThreaderBaseGlobals->m_GlobalMaximumNumberOfThreads m_NumberOfWorkUnits = std::min( m_NumberOfWorkUnits, - m_MultiThreaderBaseGlobals->m_GlobalMaximumNumberOfThreads ); + m_PimplGlobals->m_GlobalMaximumNumberOfThreads ); m_NumberOfWorkUnits = std::max( m_NumberOfWorkUnits, NumericTraits::OneValue() ); - } ThreadIdType MultiThreaderBase::GetGlobalDefaultNumberOfThreads() { - // This is called once, on-demand to ensure that m_MultiThreaderBaseGlobals is - // initialized. - static MultiThreaderBaseGlobals * multiThreaderBaseGlobals = - GetMultiThreaderBaseGlobals(); - Unused(multiThreaderBaseGlobals); + itkInitGlobalsMacro(PimplGlobals); - if( m_MultiThreaderBaseGlobals->m_GlobalDefaultNumberOfThreads == 0 ) //need to initialize + if( m_PimplGlobals->m_GlobalDefaultNumberOfThreads == 0 ) //need to initialize { ThreadIdType threadCount = 0; /* The ITK_NUMBER_OF_THREADS_ENV_LIST contains is an @@ -454,9 +350,9 @@ ThreadIdType MultiThreaderBase::GetGlobalDefaultNumberOfThreads() // verify that the default number of threads is larger than zero threadCount = std::max( threadCount, NumericTraits::OneValue() ); - m_MultiThreaderBaseGlobals->m_GlobalDefaultNumberOfThreads = threadCount; + m_PimplGlobals->m_GlobalDefaultNumberOfThreads = threadCount; } - return m_MultiThreaderBaseGlobals->m_GlobalDefaultNumberOfThreads; + return m_PimplGlobals->m_GlobalDefaultNumberOfThreads; } ThreadIdType @@ -759,15 +655,15 @@ void MultiThreaderBase::PrintSelf(std::ostream & os, Indent indent) const os << indent << "Number of Work Units: " << m_NumberOfWorkUnits << "\n"; os << indent << "Number of Threads: " << m_MaximumNumberOfThreads << "\n"; os << indent << "Global Maximum Number Of Threads: " - << m_MultiThreaderBaseGlobals->m_GlobalMaximumNumberOfThreads << std::endl; + << m_PimplGlobals->m_GlobalMaximumNumberOfThreads << std::endl; os << indent << "Global Default Number Of Threads: " - << m_MultiThreaderBaseGlobals->m_GlobalDefaultNumberOfThreads << std::endl; + << m_PimplGlobals->m_GlobalDefaultNumberOfThreads << std::endl; os << indent << "Global Default Threader Type: " - << m_MultiThreaderBaseGlobals->m_GlobalDefaultThreader << std::endl; + << m_PimplGlobals->m_GlobalDefaultThreader << std::endl; os << indent << "SingleMethod: " << m_SingleMethod << std::endl; os << indent << "SingleData: " << m_SingleData << std::endl; } -MultiThreaderBaseGlobals * MultiThreaderBase::m_MultiThreaderBaseGlobals; +MultiThreaderBaseGlobals * MultiThreaderBase::m_PimplGlobals; } diff --git a/Modules/Core/Common/src/itkObject.cxx b/Modules/Core/Common/src/itkObject.cxx index 262dafaefb0..efaaaf98415 100644 --- a/Modules/Core/Common/src/itkObject.cxx +++ b/Modules/Core/Common/src/itkObject.cxx @@ -28,12 +28,16 @@ #include "itkCommand.h" #include +#include "itkSingleton.h" + namespace itk { /** * Initialize static member that controls warning display. */ -bool Object:: m_GlobalWarningDisplay = true; +itkGetGlobalValueMacro(Object, bool, GlobalWarningDisplay, true); + +bool * Object::m_GlobalWarningDisplay; class ITKCommon_HIDDEN Observer { @@ -477,7 +481,8 @@ void Object ::SetGlobalWarningDisplay(bool val) { - m_GlobalWarningDisplay = val; + itkInitGlobalsMacro(GlobalWarningDisplay); + *m_GlobalWarningDisplay = val; } /** @@ -487,7 +492,7 @@ bool Object ::GetGlobalWarningDisplay() { - return m_GlobalWarningDisplay; + return *Object::GetGlobalWarningDisplayPointer(); } unsigned long diff --git a/Modules/Core/Common/src/itkObjectFactoryBase.cxx b/Modules/Core/Common/src/itkObjectFactoryBase.cxx index 6cea99bf1e3..17ecf981603 100644 --- a/Modules/Core/Common/src/itkObjectFactoryBase.cxx +++ b/Modules/Core/Common/src/itkObjectFactoryBase.cxx @@ -31,88 +31,15 @@ #include "itkDynamicLoader.h" #endif #include "itkDirectory.h" +#include "itkSingleton.h" #include "itkVersion.h" #include #include - -namespace itk -{ - struct ObjectFactoryBasePrivate - { - std::list< ::itk::ObjectFactoryBase * > * m_RegisteredFactories; - std::list< ::itk::ObjectFactoryBase * > * m_InternalFactories; - bool m_Initialized; - }; -}//end of itk namespace - namespace { -using FactoryListType = std::list< ::itk::ObjectFactoryBase * >; - -// This ensures that m_ObjectFactoryBasePrivate is has been initialized once -// the library has been loaded. In some cases, this call will perform the -// initialization. In other cases, static initializers like the IO factory -// initialization code will have done the initialization. -static ::itk::ObjectFactoryBasePrivate * - initializedObjectFactoryBasePrivate = - ::itk::ObjectFactoryBase::GetObjectFactoryBase(); - -/** \class ObjectFactoryBasePrivateInitializer - * - * \brief Initialize a ObjectFactoryBasePrivate and delete it on program - * completion. - * */ -class ObjectFactoryBasePrivateInitializer -{ -public: - using Self = ObjectFactoryBasePrivateInitializer; - - ObjectFactoryBasePrivateInitializer() = default; - - /** Delete the time stamp if it was created. */ - ~ObjectFactoryBasePrivateInitializer() - { - ::itk::ObjectFactoryBase::UnRegisterAllFactories(); - if ( m_ObjectFactoryBasePrivate->m_InternalFactories ) - { - for (auto & internalFactory : *m_ObjectFactoryBasePrivate->m_InternalFactories) - { - internalFactory->UnRegister(); - } - delete m_ObjectFactoryBasePrivate->m_InternalFactories; - m_ObjectFactoryBasePrivate->m_InternalFactories = nullptr; - } - delete m_ObjectFactoryBasePrivate; - m_ObjectFactoryBasePrivate = nullptr; - } - - /** Create the GlobalTimeStamp if needed and return it. */ - static ::itk::ObjectFactoryBasePrivate * - GetObjectFactoryBasePrivate() - { - if( !m_ObjectFactoryBasePrivate ) - { - m_ObjectFactoryBasePrivate = - new ::itk::ObjectFactoryBasePrivate(); - - // To avoid being optimized out. The compiler does not like this - // statement at a higher scope. - (void) initializedObjectFactoryBasePrivate; - } - return m_ObjectFactoryBasePrivate; - } - -private: - static ::itk::ObjectFactoryBasePrivate * - m_ObjectFactoryBasePrivate; -}; -// Takes care of cleaning up the ObjectFactoryBasePrivate -static ObjectFactoryBasePrivateInitializer ObjectFactoryBasePrivateInstance; -// Initialized by the compiler to zero -::itk::ObjectFactoryBasePrivate * - ObjectFactoryBasePrivateInitializer::m_ObjectFactoryBasePrivate; +using FactoryListType = std::list< ::itk::ObjectFactoryBase * >; // Convenience function to synchronize lists and register the new factory, // either with `RegisterFactoryInternal()` or with `RegisterFactory()`. Avoid @@ -154,8 +81,7 @@ void SynchronizeList(FactoryListType * output, } } } -} - +} // end of anonymous namespace namespace itk { @@ -173,6 +99,45 @@ namespace itk * */ +struct ObjectFactoryBasePrivate +{ + ~ObjectFactoryBasePrivate() + { + ::itk::ObjectFactoryBase::UnRegisterAllFactories(); + if ( m_InternalFactories ) + { + for ( std::list< itk::ObjectFactoryBase * >::iterator i = + m_InternalFactories->begin(); + i != m_InternalFactories->end(); ++i ) + { + (*i)->UnRegister(); + } + delete m_InternalFactories; + m_InternalFactories = nullptr; + } + } + ObjectFactoryBasePrivate() : m_RegisteredFactories(nullptr), + m_InternalFactories(nullptr), + m_Initialized(false), + m_StrictVersionChecking(false) + {} + + std::list< ::itk::ObjectFactoryBase * > * m_RegisteredFactories; + std::list< ::itk::ObjectFactoryBase * > * m_InternalFactories; + bool m_Initialized; + bool m_StrictVersionChecking; +}; + +ObjectFactoryBasePrivate * ObjectFactoryBase::GetPimplGlobalsPointer() +{ + if( m_PimplGlobals == nullptr ) + { + static auto deleteLambda = [](){ delete m_PimplGlobals; }; + m_PimplGlobals = Singleton( "ObjectFactoryBase" , SynchronizeObjectFactoryBase, deleteLambda); + } + return m_PimplGlobals; +} + /** \class StringOverMap * \brief Internal implementation class for ObjectFactorBase. @@ -197,30 +162,33 @@ class OverRideMap:public StringOverMapType * between the application's ITK version and the dynamic libraries' * ITK version. */ -bool ObjectFactoryBase::m_StrictVersionChecking = false; void ObjectFactoryBase::SetStrictVersionChecking( bool value ) { - ObjectFactoryBase::m_StrictVersionChecking = value; + itkInitGlobalsMacro(PimplGlobals); + m_PimplGlobals->m_StrictVersionChecking = value; } void ObjectFactoryBase::StrictVersionCheckingOn() { - ObjectFactoryBase::m_StrictVersionChecking = true; + itkInitGlobalsMacro(PimplGlobals); + m_PimplGlobals->m_StrictVersionChecking = true; } void ObjectFactoryBase::StrictVersionCheckingOff() { - ObjectFactoryBase::m_StrictVersionChecking = false; + itkInitGlobalsMacro(PimplGlobals); + m_PimplGlobals->m_StrictVersionChecking = false; } bool ObjectFactoryBase::GetStrictVersionChecking() { - return ObjectFactoryBase::m_StrictVersionChecking; + itkInitGlobalsMacro(PimplGlobals); + return m_PimplGlobals->m_StrictVersionChecking; } @@ -233,9 +201,8 @@ ObjectFactoryBase ::CreateInstance(const char *itkclassname) { ObjectFactoryBase::Initialize(); - ObjectFactoryBasePrivate * factoryBase = GetObjectFactoryBase(); - for (auto & registeredFactory : *factoryBase->m_RegisteredFactories) + for (auto & registeredFactory : *m_PimplGlobals->m_RegisteredFactories) { LightObject::Pointer newobject = registeredFactory->CreateObject(itkclassname); if ( newobject ) @@ -252,10 +219,9 @@ ObjectFactoryBase ::CreateAllInstance(const char *itkclassname) { ObjectFactoryBase::Initialize(); - ObjectFactoryBasePrivate * factoryBase = GetObjectFactoryBase(); std::list< LightObject::Pointer > created; - for (auto & registeredFactory : *factoryBase->m_RegisteredFactories) + for (auto & registeredFactory : *m_PimplGlobals->m_RegisteredFactories) { std::list< LightObject::Pointer > moreObjects = registeredFactory->CreateAllObject(itkclassname); created.splice(created.end(), moreObjects); @@ -270,19 +236,19 @@ void ObjectFactoryBase ::InitializeFactoryList() { - ObjectFactoryBasePrivate * factoryBase = GetObjectFactoryBase(); + itkInitGlobalsMacro(PimplGlobals); /** * Don't do anything if we are already initialized */ - if ( !factoryBase->m_RegisteredFactories ) + if ( !m_PimplGlobals->m_RegisteredFactories ) { - factoryBase->m_RegisteredFactories = new FactoryListType; + m_PimplGlobals->m_RegisteredFactories = new FactoryListType; } - if ( !factoryBase->m_InternalFactories ) + if ( !m_PimplGlobals->m_InternalFactories ) { - factoryBase->m_InternalFactories = new FactoryListType; + m_PimplGlobals->m_InternalFactories = new FactoryListType; } } @@ -293,12 +259,12 @@ void ObjectFactoryBase ::Initialize() { - ObjectFactoryBasePrivate * factoryBase = GetObjectFactoryBase(); + itkInitGlobalsMacro(PimplGlobals); - if (!factoryBase->m_Initialized || - !factoryBase->m_RegisteredFactories ) + if (!m_PimplGlobals->m_Initialized || + !m_PimplGlobals->m_RegisteredFactories ) { - factoryBase->m_Initialized = true; + m_PimplGlobals->m_Initialized = true; ObjectFactoryBase::InitializeFactoryList(); ObjectFactoryBase::RegisterInternal(); #ifdef ITK_DYNAMIC_LOADING @@ -315,18 +281,17 @@ void ObjectFactoryBase ::RegisterInternal() { - ObjectFactoryBasePrivate * factoryBase = GetObjectFactoryBase(); + itkInitGlobalsMacro(PimplGlobals); // Guarantee that no internal factories have already been registered. - itkAssertInDebugAndIgnoreInReleaseMacro( factoryBase->m_RegisteredFactories->empty() ); - factoryBase->m_RegisteredFactories->clear(); + itkAssertInDebugAndIgnoreInReleaseMacro( m_PimplGlobals->m_RegisteredFactories->empty() ); + m_PimplGlobals->m_RegisteredFactories->clear(); // Register all factories registered by the // "RegisterFactoryInternal" method - for ( auto i = factoryBase->m_InternalFactories->begin(); - i != factoryBase->m_InternalFactories->end(); ++i ) + for ( auto & internalFactory : *m_PimplGlobals->m_InternalFactories) { - factoryBase->m_RegisteredFactories->push_back( *i ); + m_PimplGlobals->m_RegisteredFactories->push_back(internalFactory); } } @@ -587,7 +552,7 @@ void ObjectFactoryBase ::RegisterFactoryInternal(ObjectFactoryBase *factory) { - ObjectFactoryBasePrivate * factoryBase = GetObjectFactoryBase(); + itkInitGlobalsMacro(PimplGlobals); if ( factory->m_LibraryHandle != nullptr ) { @@ -598,12 +563,12 @@ ::RegisterFactoryInternal(ObjectFactoryBase *factory) // libraries to be loaded and this method is called during static // initialization. ObjectFactoryBase::InitializeFactoryList(); - factoryBase->m_InternalFactories->push_back(factory); + m_PimplGlobals->m_InternalFactories->push_back(factory); factory->Register(); // if the internal factories have already been register add this one too - if ( factoryBase->m_Initialized ) + if ( m_PimplGlobals->m_Initialized ) { - factoryBase->m_RegisteredFactories->push_back(factory); + m_PimplGlobals->m_RegisteredFactories->push_back(factory); } } @@ -614,7 +579,7 @@ bool ObjectFactoryBase ::RegisterFactory(ObjectFactoryBase *factory, InsertionPositionType where, size_t position) { - ObjectFactoryBasePrivate * factoryBase = GetObjectFactoryBase(); + itkInitGlobalsMacro(PimplGlobals); if ( factory->m_LibraryHandle == nullptr ) { @@ -624,7 +589,7 @@ ::RegisterFactory(ObjectFactoryBase *factory, InsertionPositionType where, size_ else { // Factories must only be loaded once - for (auto & registeredFactory : *factoryBase->m_RegisteredFactories) + for (auto & registeredFactory : *m_PimplGlobals->m_RegisteredFactories) { if (registeredFactory->m_LibraryPath == factory->m_LibraryPath) { @@ -636,7 +601,7 @@ ::RegisterFactory(ObjectFactoryBase *factory, InsertionPositionType where, size_ if ( strcmp( factory->GetITKSourceVersion(), Version::GetITKSourceVersion() ) != 0 ) { - if ( ObjectFactoryBase::m_StrictVersionChecking ) + if ( m_PimplGlobals->m_StrictVersionChecking ) { itkGenericExceptionMacro(<< "Incompatible factory version load attempt:" << "\nRunning itk version :\n" << Version::GetITKSourceVersion() @@ -664,7 +629,7 @@ ::RegisterFactory(ObjectFactoryBase *factory, InsertionPositionType where, size_ { itkGenericExceptionMacro(<< "position argument must not be used with INSERT_AT_BACK option"); } - factoryBase->m_RegisteredFactories->push_back(factory); + m_PimplGlobals->m_RegisteredFactories->push_back(factory); break; } case INSERT_AT_FRONT: @@ -673,22 +638,21 @@ ::RegisterFactory(ObjectFactoryBase *factory, InsertionPositionType where, size_ { itkGenericExceptionMacro(<< "position argument must not be used with INSERT_AT_FRONT option"); } - factoryBase->m_RegisteredFactories->push_front(factory); + m_PimplGlobals->m_RegisteredFactories->push_front(factory); break; } case INSERT_AT_POSITION: { - const size_t numberOfFactories = factoryBase->m_RegisteredFactories->size(); + const size_t numberOfFactories = m_PimplGlobals->m_RegisteredFactories->size(); if( position < numberOfFactories ) { - auto fitr = factoryBase->m_RegisteredFactories->begin(); - + auto fitr = m_PimplGlobals->m_RegisteredFactories->begin(); while( position-- ) { ++fitr; } - factoryBase->m_RegisteredFactories->insert(fitr,factory); + m_PimplGlobals->m_RegisteredFactories->insert(fitr,factory); break; } else @@ -738,12 +702,12 @@ void ObjectFactoryBase ::DeleteNonInternalFactory( ObjectFactoryBase *factory ) { - ObjectFactoryBasePrivate * factoryBase = GetObjectFactoryBase(); + itkInitGlobalsMacro(PimplGlobals); // if factory is not internal then delete - if ( std::find( factoryBase->m_InternalFactories->begin(), - factoryBase->m_InternalFactories->end(), - factory ) == factoryBase->m_InternalFactories->end() ) + if ( std::find( m_PimplGlobals->m_InternalFactories->begin(), + m_PimplGlobals->m_InternalFactories->end(), + factory ) == m_PimplGlobals->m_InternalFactories->end() ) { factory->UnRegister(); } @@ -756,17 +720,17 @@ void ObjectFactoryBase ::UnRegisterFactory(ObjectFactoryBase *factory) { - ObjectFactoryBasePrivate * factoryBase = GetObjectFactoryBase(); + itkInitGlobalsMacro(PimplGlobals); - if ( factoryBase->m_RegisteredFactories ) + if ( m_PimplGlobals->m_RegisteredFactories ) { - for ( auto i = factoryBase->m_RegisteredFactories->begin(); - i != factoryBase->m_RegisteredFactories->end(); ++i ) + for ( auto i = m_PimplGlobals->m_RegisteredFactories->begin(); + i != m_PimplGlobals->m_RegisteredFactories->end(); ++i ) { if ( factory == *i ) { DeleteNonInternalFactory(factory); - factoryBase->m_RegisteredFactories->remove(factory); + m_PimplGlobals->m_RegisteredFactories->remove(factory); return; } } @@ -780,19 +744,19 @@ void ObjectFactoryBase ::UnRegisterAllFactories() { - ObjectFactoryBasePrivate * factoryBase = GetObjectFactoryBase(); + itkInitGlobalsMacro(PimplGlobals); - if ( factoryBase->m_RegisteredFactories ) + if ( m_PimplGlobals->m_RegisteredFactories ) { // Collect up all the library handles so they can be closed // AFTER the factory has been deleted. std::list< void * > libs; - for (auto & registeredFactory : *factoryBase->m_RegisteredFactories) + for (auto & registeredFactory : *m_PimplGlobals->m_RegisteredFactories) { libs.push_back( static_cast< void * >( registeredFactory->m_LibraryHandle ) ); } // Unregister each factory - for (auto & registeredFactory : *factoryBase->m_RegisteredFactories) + for (auto & registeredFactory : *m_PimplGlobals->m_RegisteredFactories) { DeleteNonInternalFactory(registeredFactory); } @@ -806,9 +770,9 @@ ::UnRegisterAllFactories() } } #endif - delete factoryBase->m_RegisteredFactories; - factoryBase->m_RegisteredFactories = nullptr; - factoryBase->m_Initialized = false; + delete m_PimplGlobals->m_RegisteredFactories; + m_PimplGlobals->m_RegisteredFactories = nullptr; + m_PimplGlobals->m_Initialized = false; } } @@ -930,33 +894,23 @@ ::Disable(const char *className) /** * */ -ObjectFactoryBasePrivate * -ObjectFactoryBase -::GetObjectFactoryBase() -{ - if( m_ObjectFactoryBasePrivate == nullptr ) - { - m_ObjectFactoryBasePrivate = ObjectFactoryBasePrivateInitializer::GetObjectFactoryBasePrivate(); - } - return m_ObjectFactoryBasePrivate; -} - - void ObjectFactoryBase -::SynchronizeObjectFactoryBase(ObjectFactoryBasePrivate * objectFactoryBasePrivate ) +::SynchronizeObjectFactoryBase(void * objectFactoryBasePrivate) { - static ObjectFactoryBasePrivate * factoryBase = GetObjectFactoryBase(); - (void) factoryBase; + // We need to register the previously registered factories with the new pointer. + // We keep track of the previoulsy registered factory in `previousObjectFactoryBasePrivate` + // but assign the new pointer to `m_PimplGlobals` so factories can be + // registered directly with the new pointer. ObjectFactoryBasePrivate *previousObjectFactoryBasePrivate; - previousObjectFactoryBasePrivate = m_ObjectFactoryBasePrivate; - // The global static variable needs to be updated here - m_ObjectFactoryBasePrivate = objectFactoryBasePrivate; - if(m_ObjectFactoryBasePrivate && previousObjectFactoryBasePrivate) + previousObjectFactoryBasePrivate = GetPimplGlobalsPointer(); + + m_PimplGlobals = reinterpret_cast(objectFactoryBasePrivate); + if(m_PimplGlobals && previousObjectFactoryBasePrivate) { - SynchronizeList(m_ObjectFactoryBasePrivate->m_InternalFactories, + SynchronizeList(m_PimplGlobals->m_InternalFactories, previousObjectFactoryBasePrivate->m_InternalFactories, true); - SynchronizeList(m_ObjectFactoryBasePrivate->m_RegisteredFactories, + SynchronizeList(m_PimplGlobals->m_RegisteredFactories, previousObjectFactoryBasePrivate->m_RegisteredFactories, false); } } @@ -968,12 +922,10 @@ std::list< ObjectFactoryBase * > ObjectFactoryBase ::GetRegisteredFactories() { - if( m_ObjectFactoryBasePrivate == nullptr ) - { - GetObjectFactoryBase(); - } + // static SingletonIndex * singletonIndex = SingletonIndex::GetInstance(); +// Unused(singletonIndex); ObjectFactoryBase::Initialize(); - return *m_ObjectFactoryBasePrivate->m_RegisteredFactories; + return *m_PimplGlobals->m_RegisteredFactories; } /** @@ -1045,6 +997,6 @@ ::GetLibraryPath() return m_LibraryPath.c_str(); } -ObjectFactoryBasePrivate * ObjectFactoryBase::m_ObjectFactoryBasePrivate; +ObjectFactoryBasePrivate * ObjectFactoryBase::m_PimplGlobals; } // end namespace itk diff --git a/Modules/Core/Common/src/itkSingleton.cxx b/Modules/Core/Common/src/itkSingleton.cxx new file mode 100644 index 00000000000..4fcaccbf76d --- /dev/null +++ b/Modules/Core/Common/src/itkSingleton.cxx @@ -0,0 +1,136 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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. + * + *=========================================================================*/ +#include "itkSingleton.h" + + +namespace +{ +// This ensures that m_GlobalSingletonIndex has been initialized once the library +// has been loaded. In some cases, this call will perform the initialization. +// In other cases, static initializers like the IO factory initialization code +// will have done the initialization. +::itk::SingletonIndex * initializedGlobalSingletonIndex = ::itk::SingletonIndex::GetInstance(); + +/** \class GlobalSingletonIndexInitializer + * + * \brief Initialize a GlobalSingletonIndex and delete it on program + * completion. + * */ +class GlobalSingletonIndexInitializer +{ +public: + typedef GlobalSingletonIndexInitializer Self; + typedef ::itk::SingletonIndex SingletonIndex; + + GlobalSingletonIndexInitializer() {} + + /** Delete the time stamp if it was created. */ + ~GlobalSingletonIndexInitializer() + { + delete m_GlobalSingletonIndex; + m_GlobalSingletonIndex = nullptr; + } + + /** Create the GlobalSingletonIndex if needed and return it. */ + static SingletonIndex * GetGlobalSingletonIndex() + { + if ( m_GlobalSingletonIndex == nullptr ) + { + m_GlobalSingletonIndex = new SingletonIndex; + // To avoid being optimized out. The compiler does not like this + // statement at a higher scope. + Unused(initializedGlobalSingletonIndex); + } + return m_GlobalSingletonIndex; + } + +private: + static SingletonIndex * m_GlobalSingletonIndex; +}; + +// Takes care of cleaning up the GlobalSingletonIndex +static GlobalSingletonIndexInitializer GlobalSingletonIndexInitializerInstance; +// Initialized by the compiler to zero +GlobalSingletonIndexInitializer::SingletonIndex * GlobalSingletonIndexInitializer::m_GlobalSingletonIndex; + +} // end anonymous namespace + + +// may return NULL if string is not registered already +// +// access something like a std::map or +// registered globals, it may be possible to restrict the held +// classes to be derived from itk::LightObject, so dynamic cast can +// work, and could use some type of Holder class for intrinsic types +namespace itk +{ +void * +SingletonIndex +::GetGlobalInstancePrivate( const char *globalName ) +{ + SingletonData::iterator it; + it = m_GlobalObjects.find(globalName); + if (it == m_GlobalObjects.end()) + { + return nullptr; + } + return std::get<0>(it->second); +} + +// If globalName is already registered remove it from map, +// otherwise global is added to the singleton index under globalName +bool +SingletonIndex +::SetGlobalInstancePrivate( const char * globalName, void * global, std::function func, std::function deleteFunc) +{ + m_GlobalObjects.erase(globalName); + m_GlobalObjects.insert(std::make_pair(globalName, std::make_tuple(global, func, deleteFunc) ) ); + return true; +} + +SingletonIndex * +SingletonIndex +::GetInstance() +{ + if( m_Instance == nullptr ) + { + m_Instance = GlobalSingletonIndexInitializer::GetGlobalSingletonIndex(); + } + return m_Instance; +} + +void +SingletonIndex +::SetInstance(Self *instance) +{ + m_Instance = instance; +} + + +SingletonIndex::~SingletonIndex() +{ + for(auto &pair: m_GlobalObjects) + { + std::get<2>(pair.second)(); + } +} + +SingletonIndex::Self * SingletonIndex::m_Instance; + + +} // end namespace itk diff --git a/Modules/Core/Common/src/itkThreadPool.cxx b/Modules/Core/Common/src/itkThreadPool.cxx index f6586145cff..33dfd83d3e0 100644 --- a/Modules/Core/Common/src/itkThreadPool.cxx +++ b/Modules/Core/Common/src/itkThreadPool.cxx @@ -22,89 +22,24 @@ #include "itkThreadSupport.h" #include "itkNumericTraits.h" #include "itkMultiThreaderBase.h" +#include "itkSingleton.h" #include -namespace itk -{ - struct ThreadPoolGlobals - { - ThreadPoolGlobals(){}; - // To lock on the internal variables. - std::mutex m_Mutex; - ThreadPool::Pointer m_ThreadPoolInstance; - bool m_DoNotWaitForThreads{false}; - }; -}//end of itk namespace - -namespace +namespace itk { -/** \brief A function which does nothing - * - * This function is to be used to mark parameters as unused to suppress - * compiler warning. It can be used when the parameter needs to be named - * (i.e. itkNotUsed cannot be used) but is not always used. It ensures - * that the parameter is not optimized out. - */ -template -void Unused( const T &) {}; - -// This ensures that m_ThreadPoolGlobals is has been initialized once -// the library has been loaded. In some cases, this call will perform the -// initialization. In other cases, static initializers like the IO factory -// initialization code will have done the initialization. -static ::itk::ThreadPoolGlobals * - initializedThreadPoolGlobals = - ::itk::ThreadPool::GetThreadPoolGlobals(); -/** \class ThreadPoolGlobalsInitializer - * - * \brief Initialize a ThreadPoolGlobals and delete it on program - * completion. - * */ -class ThreadPoolGlobalsInitializer +struct ThreadPoolGlobals { -public: - using Self = ThreadPoolGlobalsInitializer; - - ThreadPoolGlobalsInitializer() = default; - - /** Delete the thread pool globals if it was created. */ - ~ThreadPoolGlobalsInitializer() - { - delete m_ThreadPoolGlobals; - m_ThreadPoolGlobals = nullptr; - } - - /** Create the ThreadPoolGlobals if needed and return it. */ - static ::itk::ThreadPoolGlobals * GetThreadPoolGlobals() - { - if( !m_ThreadPoolGlobals ) - { - m_ThreadPoolGlobals = new ::itk::ThreadPoolGlobals; - - // To avoid being optimized out. The compiler does not like this - // statement at a higher scope. - Unused(initializedThreadPoolGlobals); - } - return m_ThreadPoolGlobals; - } - -private: - static ::itk::ThreadPoolGlobals * - m_ThreadPoolGlobals; + ThreadPoolGlobals():m_DoNotWaitForThreads(false){}; + // To lock on the internal variables. + std::mutex m_Mutex; + ThreadPool::Pointer m_ThreadPoolInstance; + bool m_DoNotWaitForThreads; }; -// Takes care of cleaning up the ThreadPoolGlobals -static ThreadPoolGlobalsInitializer ThreadPoolGlobalsInstance; -// Initialized by the compiler to zero -::itk::ThreadPoolGlobals * - ThreadPoolGlobalsInitializer::m_ThreadPoolGlobals; -}// end of anonymous namespace - -namespace itk -{ +itkGetGlobalSimpleMacro(ThreadPool, ThreadPoolGlobals, PimplGlobals); ThreadPool::Pointer ThreadPool @@ -118,65 +53,48 @@ ThreadPool::Pointer ThreadPool ::GetInstance() { - std::unique_lock mutexHolder( m_ThreadPoolGlobals->m_Mutex ); - - // This is called once, on-demand to ensure that m_ThreadPoolGlobals is + // This is called once, on-demand to ensure that m_PimplGlobals is // initialized. - static ThreadPoolGlobals * threadPoolGlobals = GetThreadPoolGlobals(); - Unused(threadPoolGlobals); + itkInitGlobalsMacro(PimplGlobals); - if( m_ThreadPoolGlobals->m_ThreadPoolInstance.IsNull() ) + if( m_PimplGlobals->m_ThreadPoolInstance.IsNull() ) { - m_ThreadPoolGlobals->m_ThreadPoolInstance = ObjectFactory< Self >::Create(); - if ( m_ThreadPoolGlobals->m_ThreadPoolInstance.IsNull() ) + std::unique_lock mutexHolder(m_PimplGlobals->m_Mutex); + // After we have the lock, double check the initialization + // flag to ensure it hasn't been changed by another thread. + if( m_PimplGlobals->m_ThreadPoolInstance.IsNull() ) { - new ThreadPool(); //constructor sets m_ThreadPoolGlobals->m_ThreadPoolInstance + m_PimplGlobals->m_ThreadPoolInstance = ObjectFactory< Self >::Create(); + if ( m_PimplGlobals->m_ThreadPoolInstance.IsNull() ) + { + new ThreadPool(); //constructor sets m_PimplGlobals->m_ThreadPoolInstance + } } } - return m_ThreadPoolGlobals->m_ThreadPoolInstance; -} - -ThreadPoolGlobals * -ThreadPool -::GetThreadPoolGlobals() -{ - if( m_ThreadPoolGlobals == nullptr ) - { - m_ThreadPoolGlobals = ThreadPoolGlobalsInitializer::GetThreadPoolGlobals(); - } - return m_ThreadPoolGlobals; -} - -void -ThreadPool -::SetThreadPoolGlobals(::itk::ThreadPoolGlobals * globals) -{ - m_ThreadPoolGlobals = globals; + return m_PimplGlobals->m_ThreadPoolInstance; } bool ThreadPool ::GetDoNotWaitForThreads() { - static ThreadPoolGlobals * threadPoolGlobals = GetThreadPoolGlobals(); - Unused(threadPoolGlobals); - return m_ThreadPoolGlobals->m_DoNotWaitForThreads; + itkInitGlobalsMacro(PimplGlobals); + return m_PimplGlobals->m_DoNotWaitForThreads; } void ThreadPool ::SetDoNotWaitForThreads(bool doNotWaitForThreads) { - static ThreadPoolGlobals * threadPoolGlobals = GetThreadPoolGlobals(); - Unused(threadPoolGlobals); - m_ThreadPoolGlobals->m_DoNotWaitForThreads = doNotWaitForThreads; + itkInitGlobalsMacro(PimplGlobals); + m_PimplGlobals->m_DoNotWaitForThreads = doNotWaitForThreads; } ThreadPool ::ThreadPool() { - m_ThreadPoolGlobals->m_ThreadPoolInstance = this; //threads need this - m_ThreadPoolGlobals->m_ThreadPoolInstance->UnRegister(); // Remove extra reference + m_PimplGlobals->m_ThreadPoolInstance = this; //threads need this + m_PimplGlobals->m_ThreadPoolInstance->UnRegister(); // Remove extra reference ThreadIdType threadCount = MultiThreaderBase::GetGlobalDefaultNumberOfThreads(); m_Threads.reserve( threadCount ); for ( unsigned int i = 0; i < threadCount; ++i ) @@ -189,7 +107,7 @@ void ThreadPool ::AddThreads(ThreadIdType count) { - std::unique_lock mutexHolder( m_ThreadPoolGlobals->m_Mutex ); + std::unique_lock mutexHolder(m_PimplGlobals->m_Mutex); m_Threads.reserve( m_Threads.size() + count ); for( unsigned int i = 0; i < count; ++i ) { @@ -201,14 +119,14 @@ std::mutex& ThreadPool ::GetMutex() { - return m_ThreadPoolGlobals->m_Mutex; + return m_PimplGlobals->m_Mutex; } int ThreadPool ::GetNumberOfCurrentlyIdleThreads() const { - std::unique_lock mutexHolder( m_ThreadPoolGlobals->m_Mutex ); + std::unique_lock mutexHolder( m_PimplGlobals->m_Mutex ); return int(m_Threads.size()) - int(m_WorkQueue.size()); // lousy approximation } @@ -224,14 +142,14 @@ ThreadPool //explicitly terminated by a call to the ExitProcess function". waitForThreads = false; #else - if(m_ThreadPoolGlobals->m_DoNotWaitForThreads) + if(m_PimplGlobals->m_DoNotWaitForThreads) { waitForThreads = false; } #endif + { + std::unique_lock< std::mutex > mutexHolder( m_PimplGlobals->m_Mutex ); - { - std::unique_lock< std::mutex > mutexHolder( m_ThreadPoolGlobals->m_Mutex ); this->m_Stopping = true; } @@ -255,14 +173,14 @@ ThreadPool ::ThreadExecute() { //plain pointer does not increase reference count - ThreadPool* threadPool = m_ThreadPoolGlobals->m_ThreadPoolInstance.GetPointer(); + ThreadPool* threadPool = m_PimplGlobals->m_ThreadPoolInstance.GetPointer(); while ( true ) { std::function< void() > task; { - std::unique_lock mutexHolder( m_ThreadPoolGlobals->m_Mutex ); + std::unique_lock mutexHolder( m_PimplGlobals->m_Mutex ); threadPool->m_Condition.wait( mutexHolder, [threadPool] { @@ -281,6 +199,6 @@ ::ThreadExecute() } } -ThreadPoolGlobals * ThreadPool::m_ThreadPoolGlobals; +ThreadPoolGlobals * ThreadPool::m_PimplGlobals; } diff --git a/Modules/Core/Common/src/itkTimeStamp.cxx b/Modules/Core/Common/src/itkTimeStamp.cxx index 2e9008ab164..f41a7a11ce4 100644 --- a/Modules/Core/Common/src/itkTimeStamp.cxx +++ b/Modules/Core/Common/src/itkTimeStamp.cxx @@ -27,72 +27,13 @@ *=========================================================================*/ #include "itkTimeStamp.h" -namespace -{ -/** \brief A function which does nothing - * - * This function is to be used to mark parameters as unused to suppress - * compiler warning. It can be used when the parameter needs to be named - * (i.e. itkNotUsed cannot be used) but is not always used. It ensures - * that the parameter is not optimized out. - */ -template -void Unused( const T &) {}; - -// This ensures that m_GlobalTimeStamp is has been initialized once the library -// has been loaded. In some cases, this call will perform the initialization. -// In other cases, static initializers like the IO factory initialization code -// will have done the initialization. -static ::itk::TimeStamp::GlobalTimeStampType * initializedGlobalTimeStamp = ::itk::TimeStamp::GetGlobalTimeStamp(); +#include "itkSingleton.h" -/** \class GlobalTimeStampInitializer - * - * \brief Initialize a GlobalTimeStamp and delete it on program - * completion. - * */ -class GlobalTimeStampInitializer +namespace itk { -public: - using Self = GlobalTimeStampInitializer; - using GlobalTimeStampType = ::itk::TimeStamp::GlobalTimeStampType; - - GlobalTimeStampInitializer() = default; - - /** Delete the time stamp if it was created. */ - ~GlobalTimeStampInitializer() - { - delete m_GlobalTimeStamp; - m_GlobalTimeStamp = nullptr; - } - - /** Create the GlobalTimeStamp if needed and return it. */ - static GlobalTimeStampType * GetGlobalTimeStamp() - { - if( !m_GlobalTimeStamp ) - { - m_GlobalTimeStamp = new GlobalTimeStampType( 0 ); - - // To avoid being optimized out. The compiler does not like this - // statement at a higher scope. - Unused(initializedGlobalTimeStamp); - } - return m_GlobalTimeStamp; - } - -private: - static GlobalTimeStampType * m_GlobalTimeStamp; -}; - -// Takes care of cleaning up the GlobalTimeStamp -static GlobalTimeStampInitializer GlobalTimeStampInitializerInstance; -// Initialized by the compiler to zero -GlobalTimeStampInitializer::GlobalTimeStampType * GlobalTimeStampInitializer::m_GlobalTimeStamp; - -} // end anonymous namespace +itkGetGlobalValueMacro(TimeStamp, TimeStamp::GlobalTimeStampType, GlobalTimeStamp, 0); -namespace itk -{ /** * Instance creation. @@ -105,25 +46,6 @@ ::New() } -TimeStamp::GlobalTimeStampType * -TimeStamp -::GetGlobalTimeStamp() -{ - if( m_GlobalTimeStamp == nullptr ) - { - m_GlobalTimeStamp = GlobalTimeStampInitializer::GetGlobalTimeStamp(); - } - return m_GlobalTimeStamp; -} - - -void -TimeStamp -::SetGlobalTimeStamp( GlobalTimeStampType * timeStamp ) -{ - m_GlobalTimeStamp = timeStamp; -} - /** * Make sure the new time stamp is greater than all others so far. */ @@ -133,12 +55,10 @@ ::Modified() { // This is called once, on-demand to ensure that m_GlobalTimeStamp is // initialized. - static GlobalTimeStampType * globalTimeStamp = GetGlobalTimeStamp(); - Unused(globalTimeStamp); + itkInitGlobalsMacro(GlobalTimeStamp); this->m_ModifiedTime = ++(*m_GlobalTimeStamp); } TimeStamp::GlobalTimeStampType * TimeStamp::m_GlobalTimeStamp; - } // end namespace itk diff --git a/Modules/Filtering/FFT/include/itkFFTWGlobalConfiguration.h b/Modules/Filtering/FFT/include/itkFFTWGlobalConfiguration.h index 00513bd382b..85484c02a0c 100644 --- a/Modules/Filtering/FFT/include/itkFFTWGlobalConfiguration.h +++ b/Modules/Filtering/FFT/include/itkFFTWGlobalConfiguration.h @@ -25,7 +25,7 @@ #include "ITKFFTExport.h" #include - +#include "itkSingletonMacro.h" #include "itksys/SystemTools.hxx" #include "itksys/SystemInformation.hxx" #if defined( ITK_USE_CUFFTW ) @@ -36,6 +36,8 @@ #include #include +struct FFTWGlobalConfigurationGlobals; + //* The fftw utilities help control the various strategies //available for controlling optimizations for the FFTW library. // @@ -64,6 +66,9 @@ namespace itk * A set of functions for defining wisdom filename * generation strategies. */ + +struct FFTWGlobalConfigurationGlobals; + #ifdef _WIN32 #define FFTWPathSep "\\" #else @@ -297,14 +302,16 @@ class ITKFFT_EXPORT FFTWGlobalConfiguration /** Return the singleton instance with no reference counting. */ static Pointer GetInstance(); + itkGetGlobalDeclarationMacro(FFTWGlobalConfigurationGlobals, PimplGlobals); + + /** This is a singleton pattern New. There will only be ONE * reference to a FFTWGlobalConfiguration object per process. * The single instance will be unreferenced when * the program exits. */ itkFactorylessNewMacro(Self); - static Pointer m_Instance; - static std::mutex m_CreationLock; + static FFTWGlobalConfigurationGlobals *m_PimplGlobals; std::mutex m_Lock; bool m_NewWisdomAvailable; diff --git a/Modules/Filtering/FFT/src/itkFFTWGlobalConfiguration.cxx b/Modules/Filtering/FFT/src/itkFFTWGlobalConfiguration.cxx index e535bd36770..0cf743c15bb 100644 --- a/Modules/Filtering/FFT/src/itkFFTWGlobalConfiguration.cxx +++ b/Modules/Filtering/FFT/src/itkFFTWGlobalConfiguration.cxx @@ -16,7 +16,12 @@ * *=========================================================================*/ #include "itkFFTWGlobalConfiguration.h" + #if defined(ITK_USE_FFTWF) || defined(ITK_USE_FFTWD) + +#include "itkSingleton.h" + + #include "itksys/SystemTools.hxx" #ifdef _WIN32 #include @@ -37,6 +42,15 @@ namespace itk { +struct FFTWGlobalConfigurationGlobals +{ + FFTWGlobalConfigurationGlobals():m_Instance(nullptr) + {}; + + FFTWGlobalConfiguration::Pointer m_Instance; + std::mutex m_CreationLock; +}; + WisdomFilenameGeneratorBase ::WisdomFilenameGeneratorBase() { @@ -137,23 +151,25 @@ static bool isDeclineString(std::string response) return false; } -std::mutex itk::FFTWGlobalConfiguration::m_CreationLock; -itk::FFTWGlobalConfiguration::Pointer itk::FFTWGlobalConfiguration::m_Instance=nullptr; +itkGetGlobalSimpleMacro(FFTWGlobalConfiguration, FFTWGlobalConfigurationGlobals, PimplGlobals); + +FFTWGlobalConfigurationGlobals * FFTWGlobalConfiguration::m_PimplGlobals; FFTWGlobalConfiguration::Pointer FFTWGlobalConfiguration ::GetInstance() { - if( ! FFTWGlobalConfiguration::m_Instance ) + itkInitGlobalsMacro(PimplGlobals); + if( ! m_PimplGlobals->m_Instance ) { - FFTWGlobalConfiguration::m_CreationLock.lock(); + m_PimplGlobals->m_CreationLock.lock(); //Need to make sure that during gaining access //to the lock that some other thread did not //initialize the singleton. - if( ! FFTWGlobalConfiguration::m_Instance ) + if( ! m_PimplGlobals->m_Instance ) { - FFTWGlobalConfiguration::m_Instance= Self::New(); - if ( ! FFTWGlobalConfiguration::m_Instance ) + m_PimplGlobals->m_Instance= Self::New(); + if ( ! m_PimplGlobals->m_Instance ) { std::ostringstream message; message << "itk::ERROR: " << "FFTWGlobalConfiguration" @@ -162,9 +178,9 @@ ::GetInstance() throw e_; /* Explicit naming to work around Intel compiler bug. */ } } - FFTWGlobalConfiguration::m_CreationLock.unlock(); + m_PimplGlobals->m_CreationLock.unlock(); } - return FFTWGlobalConfiguration::m_Instance; + return m_PimplGlobals->m_Instance; } HardwareWisdomFilenameGenerator @@ -801,6 +817,7 @@ void FFTWGlobalConfiguration ::SetNewWisdomAvailable( const bool & v ) { + itkInitGlobalsMacro(PimplGlobals); GetInstance()->m_NewWisdomAvailable = v; } @@ -808,6 +825,7 @@ bool FFTWGlobalConfiguration ::GetNewWisdomAvailable() { + itkInitGlobalsMacro(PimplGlobals); return GetInstance()->m_NewWisdomAvailable; } @@ -815,6 +833,7 @@ void FFTWGlobalConfiguration ::SetPlanRigor( const int & v ) { + itkInitGlobalsMacro(PimplGlobals); // use that method to check the value GetPlanRigorName( v ); GetInstance()->m_PlanRigor = v; @@ -824,6 +843,7 @@ int FFTWGlobalConfiguration ::GetPlanRigor() { + itkInitGlobalsMacro(PimplGlobals); return GetInstance()->m_PlanRigor; } @@ -831,6 +851,7 @@ void FFTWGlobalConfiguration ::SetPlanRigor( const std::string & name ) { + itkInitGlobalsMacro(PimplGlobals); SetPlanRigor( GetPlanRigorValue( name ) ); } @@ -838,6 +859,7 @@ void FFTWGlobalConfiguration ::SetReadWisdomCache( const bool & v ) { + itkInitGlobalsMacro(PimplGlobals); GetInstance()->m_ReadWisdomCache = v; if(v == true) { @@ -849,6 +871,7 @@ bool FFTWGlobalConfiguration ::GetReadWisdomCache() { + itkInitGlobalsMacro(PimplGlobals); return GetInstance()->m_ReadWisdomCache; } @@ -856,6 +879,7 @@ void FFTWGlobalConfiguration ::SetWriteWisdomCache( const bool & v ) { + itkInitGlobalsMacro(PimplGlobals); GetInstance()->m_WriteWisdomCache = v; } @@ -863,6 +887,7 @@ bool FFTWGlobalConfiguration ::GetWriteWisdomCache() { + itkInitGlobalsMacro(PimplGlobals); return GetInstance()->m_WriteWisdomCache; } @@ -871,6 +896,7 @@ void FFTWGlobalConfiguration ::SetWisdomCacheBase( const std::string & v ) { + itkInitGlobalsMacro(PimplGlobals); GetInstance()->m_WisdomCacheBase = v; //If resetting the wisdom cache base, we need to re-read the wisdom files ImportDefaultWisdomFile(); @@ -880,6 +906,8 @@ std::string FFTWGlobalConfiguration ::GetWisdomCacheBase() { + itkInitGlobalsMacro(PimplGlobals); + return GetInstance()->m_WisdomCacheBase; } diff --git a/Modules/IO/Meta/include/itkMetaImageIO.h b/Modules/IO/Meta/include/itkMetaImageIO.h index 4517e1ccd81..32c8de705d2 100644 --- a/Modules/IO/Meta/include/itkMetaImageIO.h +++ b/Modules/IO/Meta/include/itkMetaImageIO.h @@ -22,6 +22,7 @@ #include #include "itkImageIOBase.h" +#include "itkSingletonMacro.h" #include "metaObject.h" #include "metaImage.h" @@ -171,12 +172,14 @@ class ITKIOMeta_EXPORT MetaImageIO:public ImageIOBase void PrintSelf(std::ostream & os, Indent indent) const override; private: + /** Only used to synchronize the global variable across static libraries.*/ + itkGetGlobalDeclarationMacro(unsigned int, DefaultDoublePrecision); MetaImage m_MetaImage; unsigned int m_SubSamplingFactor; - static unsigned int m_DefaultDoublePrecision; + static unsigned int * m_DefaultDoublePrecision; }; } // end namespace itk diff --git a/Modules/IO/Meta/src/itkMetaImageIO.cxx b/Modules/IO/Meta/src/itkMetaImageIO.cxx index 8dc9c78dff5..dc7cab2c15e 100644 --- a/Modules/IO/Meta/src/itkMetaImageIO.cxx +++ b/Modules/IO/Meta/src/itkMetaImageIO.cxx @@ -22,15 +22,19 @@ #include "itkIOCommon.h" #include "itksys/SystemTools.hxx" #include "itkMath.h" +#include "itkSingleton.h" namespace itk { // Explicitly set std::numeric_limits::max_digits10 this will provide // better accuracy when writing out floating point number in MetaImage header. -unsigned int MetaImageIO::m_DefaultDoublePrecision = 17; +itkGetGlobalValueMacro(MetaImageIO, unsigned int, DefaultDoublePrecision, 17); + +unsigned int * MetaImageIO::m_DefaultDoublePrecision; MetaImageIO::MetaImageIO() { + itkInitGlobalsMacro(DefaultDoublePrecision); m_FileType = Binary; m_SubSamplingFactor = 1; if ( MET_SystemByteOrderMSB() ) @@ -1298,12 +1302,14 @@ MetaImageIO::GetSplitRegionForWriting( unsigned int ithPiece, void MetaImageIO::SetDefaultDoublePrecision(unsigned int precision) { - m_DefaultDoublePrecision = precision; + itkInitGlobalsMacro(DefaultDoublePrecision); + *m_DefaultDoublePrecision = precision; } unsigned int MetaImageIO::GetDefaultDoublePrecision() { - return m_DefaultDoublePrecision; + itkInitGlobalsMacro(DefaultDoublePrecision); + return *MetaImageIO::GetDefaultDoublePrecisionPointer(); } } // end namespace itk diff --git a/Wrapping/Generators/Python/CMakeLists.txt b/Wrapping/Generators/Python/CMakeLists.txt index ab25746d75d..f0a4544ebac 100644 --- a/Wrapping/Generators/Python/CMakeLists.txt +++ b/Wrapping/Generators/Python/CMakeLists.txt @@ -399,56 +399,32 @@ macro(itk_end_wrap_module_python) set(ITK_WRAP_PYTHON_GLOBAL_TIMESTAMP_CALLS ) if(NOT BUILD_SHARED_LIBS) if(WRAPPER_LIBRARY_NAME STREQUAL "ITKCommon") + + if(WIN32) + set(DO_NOT_WAIT_FOR_THREADS_DECLS "#include \"itkThreadPool.h\"") + set(DO_NOT_WAIT_FOR_THREADS_CALLS "itk::ThreadPool::SetDoNotWaitForThreads( true );") + endif() + set(ITK_WRAP_PYTHON_GLOBAL_TIMESTAMP_DECLS " #define _ITKCommonPython_MODULE #include \"itkPyITKCommonCAPI.h\" +${DO_NOT_WAIT_FOR_THREADS_DECLS} static -_ITKCommonPython_GetGlobalTimeStamp_RETURN -_ITKCommonPython_GetGlobalTimeStamp -_ITKCommonPython_GetGlobalTimeStamp_PROTO +_ITKCommonPython_GetGlobalSingletonIndex_RETURN +_ITKCommonPython_GetGlobalSingletonIndex +_ITKCommonPython_GetGlobalSingletonIndex_PROTO { - return itk::TimeStamp::GetGlobalTimeStamp(); -} - -static -_ITKCommonPython_GetObjectFactoryBase_RETURN -_ITKCommonPython_GetObjectFactoryBase -_ITKCommonPython_GetObjectFactoryBase_PROTO -{ - return itk::ObjectFactoryBase::GetObjectFactoryBase(); -} - -static -_ITKCommonPython_GetThreadPoolGlobals_RETURN -_ITKCommonPython_GetThreadPoolGlobals -_ITKCommonPython_GetThreadPoolGlobals_PROTO -{ - return itk::ThreadPool::GetThreadPoolGlobals(); -} - -static -_ITKCommonPython_GetMultiThreaderBaseGlobals_RETURN -_ITKCommonPython_GetMultiThreaderBaseGlobals -_ITKCommonPython_GetMultiThreaderBaseGlobals_PROTO -{ - return itk::MultiThreaderBase::GetMultiThreaderBaseGlobals(); + return itk::SingletonIndex::GetInstance(); } ") -if(WIN32) - set(DO_NOT_WAIT_FOR_THREADS "itk::ThreadPool::SetDoNotWaitForThreads( true );") -endif() - set(ITK_WRAP_PYTHON_GLOBAL_TIMESTAMP_CALLS " static void * _ITKCommonPython_API[_ITKCommonPython_API_pointers]; /* Initialize the C API pointer array */ - _ITKCommonPython_API[_ITKCommonPython_GetGlobalTimeStamp_NUM] = (void *)_ITKCommonPython_GetGlobalTimeStamp; - _ITKCommonPython_API[_ITKCommonPython_GetObjectFactoryBase_NUM] = (void *)_ITKCommonPython_GetObjectFactoryBase; - _ITKCommonPython_API[_ITKCommonPython_GetThreadPoolGlobals_NUM] = (void *)_ITKCommonPython_GetThreadPoolGlobals; - _ITKCommonPython_API[_ITKCommonPython_GetMultiThreaderBaseGlobals_NUM] = (void *)_ITKCommonPython_GetMultiThreaderBaseGlobals; + _ITKCommonPython_API[_ITKCommonPython_GetGlobalSingletonIndex_NUM] = (void *)_ITKCommonPython_GetGlobalSingletonIndex; /* Create a Capsule containing the API pointer array's address */ PyObject * cAPIObject = PyCapsule_New((void *)_ITKCommonPython_API, @@ -458,11 +434,12 @@ endif() { PyModule_AddObject( m, \"_C_API\", cAPIObject ); } - ${DO_NOT_WAIT_FOR_THREADS} + ${DO_NOT_WAIT_FOR_THREADS_CALLS} ") elseif("ITKCommon" IN_LIST WRAPPER_LIBRARY_LINK_LIBRARIES) set(ITK_WRAP_PYTHON_GLOBAL_TIMESTAMP_DECLS " #include \"itkPyITKCommonCAPI.h\" +${DO_NOT_WAIT_FOR_THREADS_DECLS} ") set(ITK_WRAP_PYTHON_GLOBAL_TIMESTAMP_CALLS " if( import__ITKCommonPython() < 0 ) @@ -473,11 +450,8 @@ endif() return; #endif } - itk::TimeStamp::SetGlobalTimeStamp( _ITKCommonPython_GetGlobalTimeStamp() ); - itk::ObjectFactoryBase::SynchronizeObjectFactoryBase( _ITKCommonPython_GetObjectFactoryBase() ); - itk::ThreadPool::SetThreadPoolGlobals( _ITKCommonPython_GetThreadPoolGlobals() ); - itk::MultiThreaderBase::SetMultiThreaderBaseGlobals( _ITKCommonPython_GetMultiThreaderBaseGlobals() ); - ${DO_NOT_WAIT_FOR_THREADS} + itk::SingletonIndex::SetInstance( _ITKCommonPython_GetGlobalSingletonIndex() ); + ${DO_NOT_WAIT_FOR_THREADS_CALLS} ") endif() endif() diff --git a/Wrapping/Generators/Python/itkPyITKCommonCAPI.h b/Wrapping/Generators/Python/itkPyITKCommonCAPI.h index c9c0ff6b855..0a64c60faa9 100644 --- a/Wrapping/Generators/Python/itkPyITKCommonCAPI.h +++ b/Wrapping/Generators/Python/itkPyITKCommonCAPI.h @@ -18,10 +18,7 @@ #ifndef itkPyITKCommonCAPI_h #define itkPyITKCommonCAPI_h -#include "itkTimeStamp.h" -#include "itkObjectFactoryBase.h" -#include "itkThreadPool.h" -#include "itkMultiThreaderBase.h" +#include "itkSingleton.h" /* Header file for the _ITKCommonPython C API exposed via an PyCapsule. * @@ -40,47 +37,26 @@ extern "C" { #endif /* C API functions */ -#define _ITKCommonPython_GetGlobalTimeStamp_NUM 0 -#define _ITKCommonPython_GetGlobalTimeStamp_RETURN itk::TimeStamp::GlobalTimeStampType * -#define _ITKCommonPython_GetGlobalTimeStamp_PROTO () +#define _ITKCommonPython_GetGlobalSingletonIndex_NUM 0 +#define _ITKCommonPython_GetGlobalSingletonIndex_RETURN itk::SingletonIndex * +#define _ITKCommonPython_GetGlobalSingletonIndex_PROTO () -#define _ITKCommonPython_GetObjectFactoryBase_NUM 1 -#define _ITKCommonPython_GetObjectFactoryBase_RETURN itk::ObjectFactoryBasePrivate * -#define _ITKCommonPython_GetObjectFactoryBase_PROTO () - -#define _ITKCommonPython_GetThreadPoolGlobals_NUM 2 -#define _ITKCommonPython_GetThreadPoolGlobals_RETURN itk::ThreadPoolGlobals * -#define _ITKCommonPython_GetThreadPoolGlobals_PROTO () - -#define _ITKCommonPython_GetMultiThreaderBaseGlobals_NUM 3 -#define _ITKCommonPython_GetMultiThreaderBaseGlobals_RETURN itk::MultiThreaderBaseGlobals * -#define _ITKCommonPython_GetMultiThreaderBaseGlobals_PROTO () /* Total number of C API pointers */ -#define _ITKCommonPython_API_pointers 4 +#define _ITKCommonPython_API_pointers 1 #ifdef _ITKCommonPython_MODULE /* This section is used when compiling ITKCommonPython.cpp */ -static _ITKCommonPython_GetGlobalTimeStamp_RETURN _ITKCommonPython_GetGlobalTimeStamp _ITKCommonPython_GetGlobalTimeStamp_PROTO; -static _ITKCommonPython_GetObjectFactoryBase_RETURN _ITKCommonPython_GetObjectFactoryBase _ITKCommonPython_GetObjectFactoryBase_PROTO; -static _ITKCommonPython_GetThreadPoolGlobals_RETURN _ITKCommonPython_GetThreadPoolGlobals _ITKCommonPython_GetThreadPoolGlobals_PROTO; -static _ITKCommonPython_GetMultiThreaderBaseGlobals_RETURN _ITKCommonPython_GetMultiThreaderBaseGlobals _ITKCommonPython_GetMultiThreaderBaseGlobals_PROTO; +static _ITKCommonPython_GetGlobalSingletonIndex_RETURN _ITKCommonPython_GetInstance _ITKCommonPython_GetGlobalSingletonIndex_PROTO; #else /* This section is used in modules that use _ITKCommonPython's C API */ static void **_ITKCommonPython_API; -#define _ITKCommonPython_GetGlobalTimeStamp \ - (*(_ITKCommonPython_GetGlobalTimeStamp_RETURN (*)_ITKCommonPython_GetGlobalTimeStamp_PROTO) _ITKCommonPython_API[_ITKCommonPython_GetGlobalTimeStamp_NUM]) -#define _ITKCommonPython_GetObjectFactoryBase \ - (*(_ITKCommonPython_GetObjectFactoryBase_RETURN (*)_ITKCommonPython_GetObjectFactoryBase_PROTO) _ITKCommonPython_API[_ITKCommonPython_GetObjectFactoryBase_NUM]) -#define _ITKCommonPython_GetThreadPoolGlobals \ - (*(_ITKCommonPython_GetThreadPoolGlobals_RETURN (*)_ITKCommonPython_GetThreadPoolGlobals_PROTO) _ITKCommonPython_API[_ITKCommonPython_GetThreadPoolGlobals_NUM]) -#define _ITKCommonPython_GetMultiThreaderBaseGlobals \ - (*(_ITKCommonPython_GetMultiThreaderBaseGlobals_RETURN (*)_ITKCommonPython_GetMultiThreaderBaseGlobals_PROTO) _ITKCommonPython_API[_ITKCommonPython_GetMultiThreaderBaseGlobals_NUM]) - +#define _ITKCommonPython_GetGlobalSingletonIndex \ + (*(_ITKCommonPython_GetGlobalSingletonIndex_RETURN (*)_ITKCommonPython_GetGlobalSingletonIndex_PROTO) _ITKCommonPython_API[_ITKCommonPython_GetGlobalSingletonIndex_NUM]) /* Return -1 on error, 0 on success. * PyCapsule_Import will set an exception if there's an error. */