base::AtExitManager 和 base::Singleton 的结合使用

单例模式(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 内部会有一个链表维护这些实例,这样析构时也会逐个释放

一些有用的文章:

 

原文链接: https://www.cnblogs.com/strive-sun/p/16825459.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    base::AtExitManager 和 base::Singleton 的结合使用

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/404422

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月25日 下午4:34
下一篇 2023年4月25日 下午4:34

相关推荐