单例模式(Singleton)也称为单件模式,其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。有很多地方需要这样的功能模块,如系统的日志输出,GUI 应用必须是单鼠标,操作系统只会弹出一个任务管理器等。
在我们的项目中使用了 Chrome 提供的 base::AtExitManager 类
该类负责类的内存回收问题,AtExitManager 模仿的就是 atexit 函数的功能,使用的时候,可以在 WinMain 函数中定义一个 AtExitManager 实例:
base::AtExitManager exit_manager;
在需要创建单例的地方使用 base::Singleton,官方的 singleton.h 提供了一个例子
// Example usage: // // In your header: namespace base { template <typename T> struct DefaultSingletonTraits; } class FooClass { public: static FooClass* GetInstance(); <-- See comment below on this. void Bar() { ... } private: FooClass() { ... } friend struct base::DefaultSingletonTraits<FooClass>; DISALLOW_COPY_AND_ASSIGN(FooClass); }; // In your source file: #include "base/memory/singleton.h" FooClass* FooClass::GetInstance() { return base::Singleton<FooClass>::get(); }
简单的说就是创建一个 GetInstance 方法,再用 base::Singleton 提供的方法创建一个指针,这个指针指向类的对象,创建对象的方法被隐藏在 base::Singleton 中,我们在调用类的方法时候,只需要
FooClass::GetInstance->bar();
好奇该类如何被创建的,可以看它的源码,大致是这样
template <typename Type, typename Traits = DefaultSingletonTraits<Type>, typename DifferentiatingType = Type> class Singleton { private: // Classes using the Singleton<T> pattern should declare a GetInstance() // method and call Singleton::get() from within that. friend Type* Type::GetInstance(); // Allow TraceLog tests to test tracing after OnExit. friend class internal::DeleteTraceLogForTesting; // This class is safe to be constructed and copy-constructed since it has no // member. // Return a pointer to the one true instance of the class. static Type* get() { #if DCHECK_IS_ON() // Avoid making TLS lookup on release builds. /* if (!Traits::kAllowedToAccessOnNonjoinableThread) ThreadRestrictions::AssertSingletonAllowed(); */ #endif // The load has acquire memory ordering as the thread which reads the // instance_ pointer must acquire visibility over the singleton data. subtle::AtomicWord value = subtle::Acquire_Load(&instance_); if (value != 0 && value != internal::kBeingCreatedMarker) { return reinterpret_cast<Type*>(value); } // Object isn't created yet, maybe we will get to create it, let's try... if (subtle::Acquire_CompareAndSwap(&instance_, 0, internal::kBeingCreatedMarker) == 0) { // instance_ was NULL and is now kBeingCreatedMarker. Only one thread // will ever get here. Threads might be spinning on us, and they will // stop right after we do this store. Type* newval = Traits::New(); // Releases the visibility over instance_ to the readers. subtle::Release_Store(&instance_, reinterpret_cast<subtle::AtomicWord>(newval)); if (newval != NULL && Traits::kRegisterAtExit) AtExitManager::RegisterCallback(OnExit, NULL); return newval; } // We hit a race. Wait for the other thread to complete it. value = internal::WaitForInstance(&instance_); return reinterpret_cast<Type*>(value); } // Adapter function for use with AtExit(). This should be called single // threaded, so don't use atomic operations. // Calling OnExit while singleton is in use by other threads is a mistake. static void OnExit(void* /*unused*/) { // AtExit should only ever be register after the singleton instance was // created. We should only ever get here with a valid instance_ pointer. Traits::Delete(reinterpret_cast<Type*>(subtle::NoBarrier_Load(&instance_))); instance_ = 0; } static subtle::AtomicWord instance_; }; template <typename Type, typename Traits, typename DifferentiatingType> subtle::AtomicWord Singleton<Type, Traits, DifferentiatingType>::instance_ = 0; } // namespace base
也就是上图标红的一行,如下,
Type* newval = Traits::New();
单例创建完后,又是如何析构的呢,base::AtExitManager 帮我们做好了,看下面源码,
AtExitManager::~AtExitManager() { if (!g_top_manager) { NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager"; return; } DCHECK_EQ(this, g_top_manager); if (!g_disable_managers) ProcessCallbacksNow(); g_top_manager = next_manager_; } // static void AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) { DCHECK(func); RegisterTask(base::Bind(func, param)); }
我们开头提到在 WinMain 函数中定义一个 AtExitManager 实例,程序结束后,栈上的内存自动释放,这时调用 AtExitManager 的析构函数释放使用 RegisterCallback 函数注册的回调函数
因为 base::Singleton 创建单例的时候自动注册了回调函数,见上面 base::Singleton 第二个标红处,如下,
AtExitManager::RegisterCallback(OnExit, NULL);
base::AtExitManager 内部会有一个链表维护这些实例,这样析构时也会逐个释放
一些有用的文章:
标签:Singleton,GetInstance,instance,base,subtle,AtExitManager From: https://www.cnblogs.com/strive-sun/p/16825459.html