使用实例
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_ 表示预申请的空间地址。