// // Copyright 2016 Pixar // // Licensed under the Apache License, Version 2.0 (the "Apache License") // with the following modification; you may not use this file except in // compliance with the Apache License and the following modification to it: // Section 6. Trademarks. is deleted and replaced with: // // 6. Trademarks. This License does not grant permission to use the trade // names, trademarks, service marks, or product names of the Licensor // and its affiliates, except as required to comply with Section 4(c) of // the License and to reproduce the content of the NOTICE file. // // You may obtain a copy of the Apache License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the Apache License with the above modification is // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // #ifndef PXR_BASE_TF_SINGLETON_H #define PXR_BASE_TF_SINGLETON_H /// \file tf/singleton.h /// \ingroup group_tf_ObjectCreation /// Manage a single instance of an object. /// /// Many classes (for example, registries) should have only a single, globally /// available instance that is created as needed on demand. This is a classic /// design pattern known as a \e singleton. Additionally, creation of this /// class (though not access to it per se) must be made threadsafe. /// /// There are two possibilities in creating a singleton: you can create a /// class all of whose member functions and variables are static, and let /// users access this class. Unfortunately, instantiating the static /// variables of this class is prone to difficulty; more importantly, should /// you change your mind and wish to allow multiple instances of the class, /// much rewriting follows. /// /// A better solution is to define the class with regular members and /// variables, and then permit only a single instance of the class to exist. /// This is the philosophy embodied by the \c TfSingleton template. It takes /// care of both multithreaded initialization and initialization before main; /// the cost of this is quite low (a single boolean comparison to access the /// instanced object after initial creation). The \c TfSingleton template /// works in conjunction with a macro in the source file /// TF_INSTANTIATE_SINGLETON(), which is itself defined by including the file /// "pxr/base/tf/instantiateSingleton.h". /// /// \anchor TfSingleton_typicalUse /// Typical Use /// /// The typical use of \c TfSingleton is as follows: /// \code /// // file: registry.h /// #include "pxr/base/tf/singleton.h" /// #include /// /// class Registry : boost::noncopyable { /// public: /// static Registry& GetInstance() { /// return TfSingleton::GetInstance(); /// } /// /// ... /// /// private: /// Registry(); /// ~Registry(); /// /// friend class TfSingleton; /// }; /// /// // file: Registry.cpp /// #include "common/astrology/registry.h" /// #include "pxr/base/tf/instantiateSingleton.h" /// /// TF_INSTANTIATE_SINGLETON(Registry); /// /// /// // file: RandomCode.cpp /// #include "common/astrology/registry.h" /// /// void Code() { /// Registry& r = Registry::GetInstance(); /// r.Lookup(...); /// ... /// } /// \endcode /// /// The constructor and destructor are declared private, and the singleton /// object will typically derive off of \c boost::noncopyable to prevent /// copying. Note that singleton objects quite commonly also make use of \c /// TfRegistryManager to acquire the data they need throughout a program. /// /// The friend class \c TfSingleton is the only class allowed to /// create an instance of a Registry. The helper function \c /// Registry::GetInstance() is for convenience only; one can just as well call /// the longer \c TfSingleton::GetInstance() to obtain a reference /// to the sole instance of the registry. #include "pxr/pxr.h" #include "pxr/base/arch/hints.h" #include "pxr/base/arch/pragmas.h" #include "pxr/base/tf/diagnosticLite.h" #include PXR_NAMESPACE_OPEN_SCOPE /// \class TfSingleton /// \ingroup group_tf_ObjectCreation /// /// Manage a single instance of an object (see /// /// \ref TfSingleton_typicalUse "Typical Use" for a canonical example). /// template class TfSingleton { public: /// Return a reference to an object of type \c T, creating it if /// necessary. /// /// When \c GetInstance() is called for the first time, it creates an /// object of type \c T, and returns a reference to it. The type in /// question must have a default constructor (i.e. a constructor taking no /// arguments). /// /// Subsequent calls to \c GetInstance() return a reference to the same /// object. This call is threadsafe; simultaneous attempts to create an /// object result in only one object being created; locking beyond this /// (for example, letting only one thread at a time call a member /// function) are the responsibility of the class author. inline static T& GetInstance() { ARCH_PRAGMA_PUSH // Suppress warnings from clang. TfSingletons are explicitly // instantiated, so the warning around this usage is a false positive. ARCH_PRAGMA_UNDEFINED_VAR_TEMPLATE return ARCH_LIKELY(_instance) ? *_instance : _CreateInstance(); ARCH_PRAGMA_POP } /// Return whether or not the single object of type \c T is currently in /// existence. /// /// This call tests whether or not the singleton currently exists. static bool CurrentlyExists() { return _instance ? true : false; } /// Indicate that the sole instance object has already been created. /// /// This function is public, but can only be called usefully from within /// the class T itself. This function is used to allow the constructor of /// T to indicate that the sole instance of T has been created, and that /// future calls to \c GetInstance() can immediately return \p instance. /// /// The need for this function occurs when the constructor of \c T /// generates a call chain that leads to calling \c /// TfSingleton::GetInstance(). Until the constructor for \c T has /// finished, however, \c TfSingleton::GetInstance() is unable to /// return a value. Calling \c SetInstanceConstructed() allows future /// calls to \c TfSingleton::GetInstance() to return before \c T's /// constructor has finished. /// /// Be sure that \c T has been constructed (enough) before calling this /// function. Calling this function anyplace but within the call chain of /// \c T's constructor will generate a fatal coding error. static void SetInstanceConstructed(T& instance) { if (_instance) TF_FATAL_ERROR("this function may not be called after " "GetInstance() has completed"); _instance = &instance; } /// Destroy the sole instance object of type \c T, if it exists. /// /// A singleton can be destroyed by a call to \c DeleteInstance. This call /// is threadsafe in the sense that competing simultaneous calls will not /// result in double deletion; however, it is up to the user to ensure /// that the instance is not being used in one thread during an attempt to /// delete the instance from another thread. After being destroyed, a /// call to \c GetInstance() will create a new instance. static void DeleteInstance() { if (_instance) _DestroyInstance(); } private: static T& _CreateInstance(); static void _DestroyInstance(); static T* _instance; ARCH_PRAGMA_PUSH ARCH_PRAGMA_NEEDS_EXPORT_INTERFACE static std::mutex* _mutex; ARCH_PRAGMA_POP }; PXR_NAMESPACE_CLOSE_SCOPE #endif