LazyInstance

使用实例

static LazyInstance<MyClass> my_instance = LAZY_INSTANCE_INITIALIZER;
void SomeMethod()
{
    my_instance.Get().SomeMethod();  // MyClass::SomeMethod()

    MyClass* ptr = my_instance.Pointer();
}

如上是一个LazyInstance使用的例子,声明了全局变量,但系统启动的时候却不占用空间,当第一次使用的时候再在堆上申请空间,空间位于堆上,而不是位于全局静态区

简要说明

以下是针对于代码中注释的翻译:

延迟加载类管理一个单个实例,这个实例在第一次访问的时候创建。实例构造的时候注册AtExitManager,当整个程序退出的时候自动调用析构函数。延迟加载类是完全线程安全的,如果你安全的创建了它,那么这个类会进行POD初始化,它不需要静态构造函数。它有点类似Singleton,但是它可以同一个类型多个实例,每个实例管理不同的单例,它为数据预申请了空间,以避免在堆上申请类型单例的空间,这也许会帮助提高创建单例的性能,减少堆碎片,但是这要求类型是一个完全类型,使得能决定其大小。

源码分析

下面是如何获取实例指针的代码,这个函数返回一个指针。

  Type* Pointer() {
#ifndef NDEBUG
    // Avoid making TLS lookup on release builds.
    if (!Traits::kAllowedToAccessOnNonjoinableThread)
      ThreadRestrictions::AssertSingletonAllowed();
#endif
    // If any bit in the created mask is true, the instance has already been
    // fully constructed.
    static const subtle::AtomicWord kLazyInstanceCreatedMask =
        ~internal::kLazyInstanceStateCreating;

    // We will hopefully have fast access when the instance is already created.
    // Since a thread sees private_instance_ == 0 or kLazyInstanceStateCreating
    // at most once, the load is taken out of NeedsInstance() as a fast-path.
    // The load has acquire memory ordering as a thread which sees
    // private_instance_ > creating needs to acquire visibility over
    // the associated data (private_buf_). Pairing Release_Store is in
    // CompleteLazyInstance().
    subtle::AtomicWord value = subtle::Acquire_Load(&private_instance_);
    if (!(value & kLazyInstanceCreatedMask) &&
        internal::NeedsLazyInstance(&private_instance_)) {
      // Create the instance in the space provided by |private_buf_|.
      value = reinterpret_cast<subtle::AtomicWord>(
          Traits::New(private_buf_.void_data()));
      internal::CompleteLazyInstance(&private_instance_, value, this,
                                     Traits::kRegisterOnExit ? OnExit : NULL);
    }
    return instance();
  }

首先先获取全局kLazyInstanceCreatedMask掩码,还有获取类成员变量private_instance_的数据来判断实例是否已经构造,如果实例为空,掩码却为真,说明当前正在由其他线程创建该实例,那么调用NeedsLazyInstance来等待其他线程创建完成。

// TODO(joth): This function could be shared with Singleton, in place of its
// WaitForInstance() call.
bool NeedsLazyInstance(subtle::AtomicWord* state) {
  // Try to create the instance, if we're the first, will go from 0 to
  // kLazyInstanceStateCreating, otherwise we've already been beaten here.
  // The memory access has no memory ordering as state 0 and
  // kLazyInstanceStateCreating have no associated data (memory barriers are
  // all about ordering of memory accesses to *associated* data).
  if (subtle::NoBarrier_CompareAndSwap(state, 0,
                                       kLazyInstanceStateCreating) == 0)
    // Caller must create instance
    return true;

  // It's either in the process of being created, or already created. Spin.
  // The load has acquire memory ordering as a thread which sees
  // state_ == STATE_CREATED needs to acquire visibility over
  // the associated data (buf_). Pairing Release_Store is in
  // CompleteLazyInstance().
  while (subtle::Acquire_Load(state) == kLazyInstanceStateCreating) {
    PlatformThread::YieldCurrentThread();
  }
  // Someone else created the instance.
  return false;
}

这里首先判断是否有线程创建,如果有,那么我们要等待,如果没有返回真。接着我们回到Pointer()函数中,当发现我们需要创建实例的时候,我们调用Traits::New来实际的安排已经创建的空间到我们要求的实例上。

void CompleteLazyInstance(subtle::AtomicWord* state,
                          subtle::AtomicWord new_instance,
                          void* lazy_instance,
                          void (*dtor)(void*)) {
  // Instance is created, go from CREATING to CREATED.
  // Releases visibility over private_buf_ to readers. Pairing Acquire_Load's
  // are in NeedsInstance() and Pointer().
  subtle::Release_Store(state, new_instance);

  // Make sure that the lazily instantiated object will get destroyed at exit.
  if (dtor)
    AtExitManager::RegisterCallback(dtor, lazy_instance);
}

然后注册销毁函数,将地址存储在private_instance_中。
销毁函数定义如下

  static void OnExit(void* lazy_instance) {
    LazyInstance<Type, Traits>* me =
        reinterpret_cast<LazyInstance<Type, Traits>*>(lazy_instance);
    Traits::Delete(me->instance());
    subtle::NoBarrier_Store(&me->private_instance_, 0);
  }

此函数在程序退出的时候被自动调用。

数据结构解析

该类有三个重要的数据结构,如下:

// Our AtomicWord doubles as a spinlock, where a value of
// kBeingCreatedMarker means the spinlock is being held for creation.
static const subtle::AtomicWord kLazyInstanceStateCreating = 1;

subtle::AtomicWord private_instance_;

// Preallocated space for the Type instance.
base::AlignedMemory<sizeof(Type), ALIGNOF(Type)> private_buf_;

现在我们来总体分析一下这三个数据。
kLazyInstanceStateCreating用来表示当前是正在创建
private_instance_ 用来存储具体的实例地址,如果是0,则还没有创建;如果是1,则正在创建,如果是一个有效的地址,而已创建完成。
private_buf_ 表示预申请的空间地址。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值