Chromium 延迟构造实例LazyInstance

来源:互联网 发布:steam mac 存档 编辑:程序博客网 时间:2024/06/03 04:37


延迟构造实例,简单来说就是一个类在没有用到的时候先占着一个坑,只有当真正用到的时候才开始倒入资源开始构造。最常见的就是我们平时用到的单例模式,实现的代码如下:

[cpp] view plain copy
  1. template<typename Type>  
  2. class CSingleton  {    
  3.  private:    
  4.   CSingleton() {}  
  5.   static Type *m_pInstance;    
  6.  public:    
  7.   static Type * GetInstance() {    
  8.   if(m_pInstance == NULL)  
  9.     m_pInstance = new Type();    
  10.     return m_pInstance;    
  11.   }    
  12. };   
  13.    
  14. template<typename Type>  
  15. Type * CSingleton<Type>::m_pInstance = NULL;  

这个类的只有在调用GetInstance才对 m_pInstance进行初始化,就体现了用到才实例化的思想。这样做的好处是加速程序的启动过程,比如一个界面的菜单对象,当你还没有点击菜单之前就创造了,那他一定会影响软件的启动性能。在chromium中,实现延迟构造的是一个LazyInstance类,这个类比起上边这个类复杂很多,我起初也觉得上边的单例也很足够了,在深入了解LazyInstance类后,我却感觉我的见识还是太少了。

lazy_instance.h

[cpp] view plain copy
  1. template <typename Type>  
  2. struct DefaultLazyInstanceTraits {  
  3.   static const bool kRegisterOnExit = true;  
  4.   static Type* New(void* instance) {  
  5.     DCHECK_EQ(reinterpret_cast<uintptr_t>(instance) & (ALIGNOF(Type) - 1), 0u)  
  6.         << "error message";  
  7.         return new (instance) Type();  
  8.   }  
  9.   static void Delete(Type* instance) {  
  10.       instance->~Type();  
  11.   }  
  12. };  
  13. namespace internal {  
  14. template <typename Type>  
  15. struct LeakyLazyInstanceTraits {  
  16.   static const bool kRegisterOnExit = false;  
  17.   static Type* New(void* instance) {  
  18.     return DefaultLazyInstanceTraits<Type>::New(instance);  
  19.   }  
  20.   static void Delete(Type* instance) {  
  21.   }  
  22. };  
  23. static const subtle::AtomicWord kLazyInstanceStateCreating = 1;  
  24. BASE_EXPORT bool NeedsLazyInstance(subtle::AtomicWord* state);  
  25. BASE_EXPORT void CompleteLazyInstance(subtle::AtomicWord* state,  
  26.                                       subtle::AtomicWord new_instance,  
  27.                                       void* lazy_instance,  
  28.                                       void (*dtor)(void*));  
  29.   
  30. }  // namespace internal  
  31. template <typename Type, typename Traits = DefaultLazyInstanceTraits<Type> >  
  32. class LazyInstance {  
  33.  public:  
  34.   // ~LazyInstance() {}  
  35.   typedef LazyInstance<Type, internal::LeakyLazyInstanceTraits<Type> > Leaky;  
  36.   Type& Get() {  
  37.     return *Pointer();  
  38.   }  
  39.   Type* Pointer() {  
  40.     static const subtle::AtomicWord kLazyInstanceCreatedMask =  
  41.         ~internal::kLazyInstanceStateCreating;  
  42.     subtle::AtomicWord value = subtle::Acquire_Load(&private_instance_);  
  43.     if (!(value & kLazyInstanceCreatedMask) &&  
  44.         internal::NeedsLazyInstance(&private_instance_)) {  
  45.            value = reinterpret_cast<subtle::AtomicWord>(  
  46.           Traits::New(private_buf_.void_data()));  
  47.       internal::CompleteLazyInstance(&private_instance_, value, this,  
  48.                                      Traits::kRegisterOnExit ? OnExit : NULL);  
  49.     }  
  50.     return instance();  
  51.   }  
  52.   bool operator==(Type* p) {  
  53.     switch (subtle::NoBarrier_Load(&private_instance_)) {  
  54.       case 0:  
  55.         return p == NULL;  
  56.       case internal::kLazyInstanceStateCreating:  
  57.         return static_cast<void*>(p) == private_buf_.void_data();  
  58.       default:  
  59.         return p == instance();  
  60.     }  
  61.   }  
  62.   subtle::AtomicWord private_instance_;  
  63.   base::AlignedMemory<sizeof(Type), ALIGNOF(Type)> private_buf_;  
  64.  private:  
  65.   Type* instance() {  
  66.     return reinterpret_cast<Type*>(subtle::NoBarrier_Load(&private_instance_));  
  67.   }  
  68.   static void OnExit(void* lazy_instance) {  
  69.     LazyInstance<Type, Traits>* me =  
  70.         reinterpret_cast<LazyInstance<Type, Traits>*>(lazy_instance);  
  71.     Traits::Delete(me->instance());  
  72.     subtle::NoBarrier_Store(&me->private_instance_, 0);  
  73.   }  
  74. };  

lazy_instance.cc

[cpp] view plain copy
  1. bool NeedsLazyInstance(subtle::AtomicWord* state) {  
  2.   if (subtle::NoBarrier_CompareAndSwap(state, 0,  
  3.                                        kLazyInstanceStateCreating) == 0)  
  4.     return true;  
  5.   while (subtle::Acquire_Load(state) == kLazyInstanceStateCreating) {  
  6.     PlatformThread::YieldCurrentThread();  
  7.   }  
  8.   return false;  
  9. }  
  10. void CompleteLazyInstance(subtle::AtomicWord* state,  
  11.                           subtle::AtomicWord new_instance,  
  12.                           void* lazy_instance,  
  13.                           void (*dtor)(void*)) {  
  14.   subtle::Release_Store(state, new_instance);  
  15.   if (dtor)  
  16.     AtExitManager::RegisterCallback(dtor, lazy_instance);  
  17. }  


1~12 定义DefaultLazyInstanceTraits,本身并不复杂,就是实现Type类型的构造和析构。与通常new Type()不同,它需要参数传入参数instance,这是一块可用的内存空间,7行就是在这块可用的内存空间中构造Type实例。比较难懂的只有第5行,reinterpret_cast(instance)把instance指针地址转成一个整数,ALIGNOF(Type)计算Type的对齐要求,reinterpret_cast(instance) & (ALIGNOF(Type) - 1)实际上相当于计算instance物理地址位置能不能被ALIGNOF(Type)整除,也就是满足对齐要求。举例来说就是,如果Type要求8字节对齐(如double)而给出的地址不能被8整除,就会报错(程序中的报错被我简化的)。


14~22定义DefaultLazyInstanceTraits,可以注意到它与DefaultLazyInstanceTraits的区别只是在于它Delete是空的。默认情况下,LazyInstance使用的是DefaultLazyInstanceTraits,它把Delete注册到AtExitManager,在程序退出时执行Delete析构。

 

31~74是最晦涩的一段定义,Pointer是从LazyInstance中取出实例的指针,这也是LazyInstance的核心实现

42行value中的值就是private_instance的值,在private_instance被附值之前,它保存的是LazyInstance的状态,private_instance_的初始化为0,也就是说private_instance_没有被初始化。
43~44 !(value & kLazyInstanceCreatedMask)这个分两种情况,

a、某个线程当第一次执行该语句,value的值为0,判断结果为真,进入到NeedsLazyInstance,查看lazy_instance.cc第2行,当value等于0时,把kLazyInstanceStateCreating附值给value,说明LazyInstance在实例化过程中,返回true。if语句通过,进入实例化private_instance_的阶段45~48,在实例化完成后,在CompleteLazyInstance中把实例化后的指针附值给private_instance_,表示实例化已经完成,整个过程private_instance_的值的变化是0->kLazyInstanceStateCreating->private_buf_.void_data。

b、当某一个线程在其它线程实例化过程中调用了Pointer函数,这时value的值已经被附值成kLazyInstanceStateCreating,这时候依然进入NeedsLazyInstance,但是这时value的值已经不是0,进入lazy_instance.cc的5~7行,等待实例初始化完成,返回false。该线程不会进入实例化的代码,直接返回instance()。

 

到此为止,代码的讲解已经完成,我觉得我的单例也蛮好的,为什么实现这么一个LazyInstance?

(1)无锁但是线程安全,在LazyInstance涉及数据竞争的操作只有NoBarrier_CompareAndSwap,但是InterlockedCompareExchange使用的是原子操作,原子操作在指令运行过程中阻止了其他线程对内存进行操作,这也可以理解成一种锁,但是速度会比正常的锁快。这种无锁的实现方式其实加大了代码的理解难度,这里主要应该是为了效率考虑的。从代码中可以看出,在初始化完成后,所有的代码都没有锁操作,相比通常加互斥锁或者读写锁,效率应该是更快的。

[cpp] view plain copy
  1. inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,  
  2.                                          Atomic32 old_value,  
  3.                                          Atomic32 new_value) {  
  4.   LONG result = InterlockedCompareExchange(  
  5.       reinterpret_cast<volatile LONG*>(ptr),  
  6.       static_cast<LONG>(new_value),  
  7.       static_cast<LONG>(old_value));  
  8.   return static_cast<Atomic32>(result);  
  9. }  


(2)全局变量且满足POD特性,在静态区保存,避免产生堆区的内存碎片。在LazyInstance的实现中,它是满足POD特性,POD特性简单来说就是组成对象的内存是连续的,可以直接使用memcopy进行拷贝,对象的大小是固定的。POD更详细的说明可以参考http://zh.wikipedia.org/wiki/POD_(%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1)。LazyInstance由于满足POD特性,在定义为全局变量时,它的数据都保存在静态区,并且已经为它的类型保留有空间private_buf_,从而避免使用对象时,使用new操作在堆空间中申请内存,产生碎片,而且达到了延迟构造实例的目的。

转注:有关POD特性 再看下面的转载http://blog.chinaunix.net/uid-20726927-id-2455477.html

(C++-98:1.8;5)给出的定义:
将对象的各字节拷贝到一个字节数组中,然后再将它重新拷贝到原先的对象所占的存储区中,此时该对象应该具有它原来的值。
《imperfect c++》一书中给出的定义和一些特性利用:
1、所有标量类型、POD结构类型、POD联合类型、以及这几种类型的数组、const/volatile修饰的版
   本都是POD类型。
2、POD结构/联合类型:一个聚合体(包括class),它的非static成员都不是pointer to member、
   pointer to member function、非POD结构、非POD联合,以及这些类型的数组、引用、const/
   volatile修饰的版本;并且,此聚合体不能有用户自定义constructor、destructor、assign 
   operator。
3、POD类型可以具有static成员、成员typedef、嵌套struct/class定义和成员函数/方法。
 
POD类型特性:
所有POD类型都可以作为union的成员,反之,所有非POD类型都不能作为union的成员。

POD特性利用:
我们可以利用POD类型特性来判断一个类型是否为POD类型:
 
template <typename Type>
struct must_be_pod
{
union
{
Type noname;
};
};
这个模板的意思是,只要类型Type是非POD类型,那么编译器将报错,因为Type被作为了union的一个成员。
使用示例:

class MyClass{public: MyClass() {} ~MyClass() {}private: virtual  void fun() {}}; template <typename Type>struct must_be_pod{union{Type noname;};};int main(){must_be_pod<double>   must_be_pod_;  // 正确// 编译报错// warning C4624: “must_be_pod<MyClass>”: 已将析构函数隐式定义为“已删除”// error C2280: “must_be_pod<MyClass>::must_be_pod(void)”: 尝试引用已删除的函数// 把 MyClass 的构造函数 析构函数 虚函数注释掉才可以编译通过must_be_pod<MyClass>   must_be_pod_myclass;return 0;}

   你可以将 POD 类型看作是一种来自外太空的用绿色保护层包装的数据类型,POD 意为“Plain Old Data”(译者:如果一定要译成中文,那就叫“彻头彻尾的老数据”怎么样!)这就是 POD 类型的含义。其确切定义相当粗糙(参见 C++ ISO 标准),其基本意思是 POD 类型包含与 C 兼容的原始数据。例如,结构和整型是 POD 类型,但带有用户定义的构造函数或虚拟函数的类则不是。 POD 类型没有虚拟函数,基类,用户定义的构造函数,拷贝构造,赋值操作符或析构函数。

  为了将 POD 类型概念化,你可以通过拷贝其比特来拷贝它们。此外, POD 类型可以是非初始化的。例如:

struct RECT r;                     // value undefined
POINT *ppoints = new POINT[100];   // ditto
CString s;                         // calls ctor ==> not POD
  非 POD 类型通常需要初始化,不论是调用缺省的构造函数(编译器提供的)还是自己写的构造函数。
  过去, POD 对于编写编译器或与C 兼容的 C++ 程序的人来说很重要。现在,POD 来到 .NET 的环境中。在托管 C++ 中,托管类型(包括 __value 和 __gc 两者)能包含嵌入的原生 POD 类型。 Figure 3 展示了例举说明代码。托管的 Circle 类能包含 POINT,但无法包含 CPoint 类。如果你尝试编译 pod.cpp 会报一个 C3633 错误:“Cannot define ''m_center'' as a member of managed ''Circle'' because of the presence of default constructor ''CPoint::CPoint'' on class ''CPoint''.”(译者:意思是由于类 CPoint 有缺省的构造函数‘CPoint::CPoint’,所以不能将‘m_center’定义为托管类‘Circle’的一个成员)
  .NET 限定嵌入的本地对象只能为 POD 类型的理由是这样做能安全地拷贝它们,不用担心调用构造函数,初始化虚表,或任何非 POD 类型需要的其它机制。


0 0
原创粉丝点击