STL源码剖析——空间配置器

http://blog.csdn.net/chenhanzhun/article/details/39153797

前言

    SGI STL源码下载地址

    空间配置是为存储数据提供可用的空间,在Standard Template Library(STL)中,空间配置是最底层的东西,为容器提供服务。在C++中,一般管理内存分配是使用newdelete进行操作,这两个操作都需要经过两个步骤;

new操作的步骤:(1)调用::operator new配置内存;(2)调用对象的构造函数构造对象并初始化。

delete操作步骤:(1)调用对象的析构函数析构对象;(2)调用::operator delete释放内存。例如:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. class Foo { ... };  
  2. Foo* pf = new Foo;  
  3. ...  
  4. delete pf;  

    而在STL中,空间配置在C++的基础上增加了一些特性。STL allocator 将这两个阶段分开操作,内存配置操作由空间配置器stl::alloc中的alloc::allocate(),内存释放由alloc::deallocate()负责;对象构造操作由::construct()负责,对象析构操作由::destroy()负责。SGI STL中考虑到了异常处理,内置轻量级内存池(主要用于处理小块内存的分配,应对内存碎片问题)实现,多线程中的内存分配处理(主要是针对内存池的互斥访问)等。

空间配置器的标准接口

    在SGI STL中,空间配置器(Allocator)的主要实现文件是alloc.hstl_alloc.h,标准接口位于文件stl_alloc.h588-628行;具体如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /*tihs program is in the file of stl_alloc.h from line 588 to 628 */  
  2.   
  3. template <class _Tp>  
  4. class allocator {  
  5.   typedef alloc _Alloc;          // The underlying allocator.  
  6. public:                         //数据类型的成员变量在后续章节(traits编程技巧)介绍  
  7.   typedef size_t     size_type;  
  8.   typedef ptrdiff_t  difference_type;  
  9.   typedef _Tp*       pointer;  
  10.   typedef const _Tp* const_pointer;  
  11.   typedef _Tp&       reference;  
  12.   typedef const _Tp& const_reference;  
  13.   typedef _Tp        value_type;  
  14.   
  15.   template <class _Tp1> struct rebind {//嵌套一个template,且仅包含唯一成员other,是一个typedef;  
  16.     typedef allocator<_Tp1> other;  
  17.   };  
  18.   //下面是成员函数  
  19.   allocator() __STL_NOTHROW {}  //默认构造函数,__STL_NOTHROW在 stl_config.h中定义,要么为空,要么为 throw()异常机制  
  20.   allocator(const allocator&) __STL_NOTHROW {}  //复制构造函数  
  21.   template <class _Tp1> allocator(const allocator<_Tp1>&) __STL_NOTHROW {}//泛化的复制构造函数  
  22.   ~allocator() __STL_NOTHROW {}//析构函数  
  23.   
  24.   pointer address(reference __x) const { return &__x; }//返回对象的地址  
  25.   const_pointer address(const_reference __x) const { return &__x; }//返回const对象的地址  
  26.   
  27.   // __n is permitted to be 0.  The C++ standard says nothing about what  
  28.   // the return value is when __n == 0.  
  29.   _Tp* allocate(size_type __n, const void* = 0) {// 配置空间,如果申请的空间块数不为0,那么调用 _Alloc 也即 alloc 的 allocate 函数来分配内存,  
  30.  //这里的 alloc 在 SGI STL 中默认使用的是__default_alloc_template<__NODE_ALLOCATOR_THREADS, 0>这个实现(见第402行)  
  31.     return __n != 0 ? static_cast<_Tp*>(_Alloc::allocate(__n * sizeof(_Tp)))   
  32.                     : 0;  
  33.   }  
  34.   
  35.   // __p is not permitted to be a null pointer.  
  36.   void deallocate(pointer __p, size_type __n)//释放已配置的空间  
  37.     { _Alloc::deallocate(__p, __n * sizeof(_Tp)); }  
  38.   
  39.   size_type max_size() const __STL_NOTHROW //返回可成功配置的最大值  
  40.     { return size_t(-1) / sizeof(_Tp); }  
  41.   
  42.   void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); }//构造,等同于new ((void*)p) T(x)  
  43.   void destroy(pointer __p) { __p->~_Tp(); }//析构,等同于p->~T()  
  44. };  

    在SGI STL的的stl_alloc.h文件中,可以看到有以下几种空间配置的类模板:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. template <int __inst> class __malloc_alloc_template   
  2. // Malloc-based allocator.  Typically slower than default alloc  
  3. typedef __malloc_alloc_template<0> malloc_alloc  
  4. template<class _Tp, class _Alloc> class simple_alloc  
  5. template <class _Alloc> class debug_alloc  
  6. template <bool threads, int inst> class __default_alloc_template  
  7.  // Default node allocator.  
  8. typedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0> alloc  
  9. typedef __default_alloc_template<false, 0> single_client_alloc  
  10. template <class _Tp>class allocator  
  11. template<>class allocator<void>  
  12. template <class _Tp, class _Alloc>struct __allocator  
  13. template <class _Alloc>class __allocator<void, _Alloc>  

   其中simple_alloc,debug_alloc,allocator__allocator都是对其他适配器(如__Alloc::allocate)的一个简单封装__malloc_alloc_template__default_alloc_template这两个配置器就是SGI STL配置器的重点。其中__malloc_alloc_templateSGI STL的第一级配置器,只是对系统的malloc,realloc,free函数的一个简单封装,并考虑到了分配失败后的异常处理。而__default_alloc_templateSGI STL的第二级配置器,在第一级配置器的基础上还考虑了内存碎片的问题,通过内置一个轻量级的内存池,及在多线程环境下内存池互斥访问的机制。

第一级配置器__malloc_alloc_template:异常处理

    第一级配置器内存分配失败一般是由于内存不足out-of-memory(oom),处理异常时,首先用户自己设计异常处理例程,若用户没有定义,仅仅是打印错误信息并强制退出。总的来说,就是留给用户异常处理接口和默认强制退出处理。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //异常处理  
  2. /*tihs program is in the file of stl_alloc.h*/  
  3. //line 109 to 118  
  4. class __malloc_alloc_template {  
  5.   
  6. private:  
  7. //内存不足异常处理  
  8.   static void* _S_oom_malloc(size_t);  
  9.   static void* _S_oom_realloc(void*, size_t);  
  10.   
  11. #ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG  
  12.   static void (* __malloc_alloc_oom_handler)();  
  13. #endif  
  14.   //line 141 to 146  
  15.   //指定自己的异常处理  
  16.   static void (* __set_malloc_handler(void (*__f)()))()  
  17.   {  
  18.     void (* __old)() = __malloc_alloc_oom_handler;  
  19.     __malloc_alloc_oom_handler = __f;  
  20.     return(__old);  
  21.   }  
  22. //line 152 to 155  
  23. #ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG  
  24. template <int __inst>  
  25. void (* __malloc_alloc_template<__inst>::__malloc_alloc_oom_handler)() = 0;  
  26. #endif  
  27. //line 41 to 50  
  28. #ifndef __THROW_BAD_ALLOC  
  29. #  if defined(__STL_NO_BAD_ALLOC) || !defined(__STL_USE_EXCEPTIONS)  
  30. #    include <stdio.h>  
  31. #    include <stdlib.h>  
  32. //默认的强制退出  
  33. #    define __THROW_BAD_ALLOC fprintf(stderr, "out of memory\n"); exit(1)  
  34. #  else /* Standard conforming out-of-memory handling */  
  35. #    include <new>  
  36. //抛出用户设计异常处理例程  
  37. #    define __THROW_BAD_ALLOC throw std::bad_alloc()  
  38. #  endif  
  39. #endif  

第二级配置器__default_alloc_template

    第二级配置器主要是利用内存池进行管理小内存分配问题,并且在多线程环境下内存池的互斥访问问题。第一级配置器__malloc_alloc_template只是malloc对的一层封装,没有考虑内存碎片问题。因此,第二级配置器是在第一级配置器的基础上考虑了内存碎片问题,对于申请内存大于128bytes移交给第一级配置器__malloc_alloc_template处理。对于小内存(小于128bytes)的申请,利用内存池来管理,直接从内存池分配即可,并维护自由链表,自由链表是来分配同样的小内存和回收小内存,即程序再次申请小内存直接从自由链表中分配,当小内存释放时,自由链表对其进行回收。

    为了方便管理,SGI STL第二级配置器会主动将任何小额区块的内存需求量上调为8的倍数,即若用户申请的小额区块内存不满足8的倍数时,系统自动向上取整为8的倍数。由于SGI STL第二级配置器要求小额区块的内存最大为128bytes,则自由链表的个数为16个,即128/8=16;每个链表分别维护区块内存大小为bytes

    下面给出第二级配置器处理的流程图和源代码:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /*tihs program is in the file of stl_alloc.h from line 288 to 375 */  
  2. //第二级配置器__default_alloc_template  
  3. template <bool threads, int inst>  
  4. class __default_alloc_template {  
  5.   
  6. private:  
  7.   // Really we should use static const int x = N  
  8.   // instead of enum { x = N }, but few compilers accept the former.  
  9. #if ! (defined(__SUNPRO_CC) || defined(__GNUC__))  
  10.     enum {_ALIGN = 8};//小额区块的上调边界  
  11.     enum {_MAX_BYTES = 128};//小额区块的最大内存  
  12.     enum {_NFREELISTS = 16}; // _MAX_BYTES/_ALIGN;自由链表个数  
  13. # endif  
  14.   static size_t  
  15.   _S_round_up(size_t __bytes) //函数功能:调整内存大小为8的倍数  
  16.     { return (((__bytes) + (size_t) _ALIGN-1) & ~((size_t) _ALIGN - 1)); }  
  17.   
  18. __PRIVATE:  
  19.   union _Obj {//自由链表节点属性  
  20.         union _Obj* _M_free_list_link;  
  21.         char _M_client_data[1];    /* The client sees this.        */  
  22.   };  
  23. private:  
  24. # if defined(__SUNPRO_CC) || defined(__GNUC__) || defined(__HP_aCC)  
  25.     static _Obj* __STL_VOLATILE _S_free_list[];   
  26.         // Specifying a size results in duplicate def for 4.1  
  27. # else  
  28.     static _Obj* __STL_VOLATILE _S_free_list[_NFREELISTS];   
  29. # endif  
  30.   static  size_t _S_freelist_index(size_t __bytes) {//函数功能:计算所申请区块内存在自由链表中对应的号数,从0开始  
  31.         return (((__bytes) + (size_t)_ALIGN-1)/(size_t)_ALIGN - 1);  
  32.   }  
  33.   
  34.   // Returns an object of size __n, and optionally adds to size __n free list.  
  35.   static void* _S_refill(size_t __n);//填充空间,把大小为n的内存空间加到自由链表  
  36.   // Allocates a chunk for nobjs of size size.  nobjs may be reduced  
  37.   // if it is inconvenient to allocate the requested number.  
  38.   /*从内存池中分配空间,该空间可容纳__nobjs大小为__size的区块,可能会少于__nobjs个*/  
  39.   static char* _S_chunk_alloc(size_t __size, int& __nobjs);  
  40.   
  41.   // Chunk allocation state.  
  42.   static char* _S_start_free;//内存池起始位置  
  43.   static char* _S_end_free;//内存池结束位置  
  44.   static size_t _S_heap_size;  
  45.   
  46. # ifdef __STL_THREADS  
  47.     static _STL_mutex_lock _S_node_allocator_lock;  
  48. # endif  
  49.   
  50.     // It would be nice to use _STL_auto_lock here.  But we  
  51.     // don't need the NULL check.  And we do need a test whether  
  52.     // threads have actually been started.  
  53.     class _Lock;  
  54.     friend class _Lock;  
  55.     class _Lock {//该类保证内存池在多线程环境解决互斥访问  
  56.         public:  
  57.             _Lock() { __NODE_ALLOCATOR_LOCK; }  
  58.             ~_Lock() { __NODE_ALLOCATOR_UNLOCK; }  
  59.     };  
  60.     public:  
  61.   
  62.   /* __n must be > 0      */  
  63.   static void* allocate(size_t __n)  
  64.   {  
  65.     void* __ret = 0;  
  66.   
  67.     if (__n > (size_t) _MAX_BYTES) {  
  68.       __ret = malloc_alloc::allocate(__n);//内存大于128时,采用第一级配置器处理  
  69.     }  
  70.     else {  
  71.       _Obj* __STL_VOLATILE* __my_free_list  
  72.           = _S_free_list + _S_freelist_index(__n);  
  73.       // Acquire the lock here with a constructor call.  
  74.       // This ensures that it is released in exit or during stack  
  75.       // unwinding.  
  76. #     ifndef _NOTHREADS  
  77.       /*REFERENCED*/  
  78.       _Lock __lock_instance;  
  79. #     endif  
  80.       _Obj* __RESTRICT __result = *__my_free_list;  
  81.       if (__result == 0)  
  82.         __ret = _S_refill(_S_round_up(__n));  
  83.       else {  
  84.         *__my_free_list = __result -> _M_free_list_link;  
  85.         __ret = __result;  
  86.       }  
  87.     }  
  88.   
  89.     return __ret;  
  90.   };  
  91. //初始化操作  
  92. //line from 554 to 571  
  93.   template <bool __threads, int __inst>  
  94. char* __default_alloc_template<__threads, __inst>::_S_start_free = 0;  
  95.   
  96. template <bool __threads, int __inst>  
  97. char* __default_alloc_template<__threads, __inst>::_S_end_free = 0;  
  98.   
  99. template <bool __threads, int __inst>  
  100. size_t __default_alloc_template<__threads, __inst>::_S_heap_size = 0;  
  101.   
  102. template <bool __threads, int __inst>  
  103. typename __default_alloc_template<__threads, __inst>::_Obj* __STL_VOLATILE  
  104. __default_alloc_template<__threads, __inst> ::_S_free_list[  
  105. # if defined(__SUNPRO_CC) || defined(__GNUC__) || defined(__HP_aCC)  
  106.     _NFREELISTS  
  107. # else  
  108.     __default_alloc_template<__threads, __inst>::_NFREELISTS  
  109. # endif  
  110. ] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };  

空间配置函数allocate()

  空间配置函数allocate()的具体实现步骤如下:

  1. 若用户申请的内存大于128bytes,则调用第一级配置器分配空间;
  2. 若小于128bytes检查对应的自由链表free_list,如果自由链表存在可用的区块,则直接使用,若不存在,则调用填充函数refill()为自由链表重新填充空间;

  空间配置函数allocate()的源代码如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1.  /* __n must be > 0      */  
  2.   static void* allocate(size_t __n)  
  3.   {  
  4.     void* __ret = 0;  
  5.   
  6.     if (__n > (size_t) _MAX_BYTES) {  
  7.       __ret = malloc_alloc::allocate(__n);//内存大于128时,采用第一级配置器处理  
  8.     }  
  9.     else {  
  10.       _Obj* __STL_VOLATILE* __my_free_list  
  11.           = _S_free_list + _S_freelist_index(__n);  
  12.       // Acquire the lock here with a constructor call.  
  13.       // This ensures that it is released in exit or during stack  
  14.       // unwinding.  
  15. #     ifndef _NOTHREADS  
  16.       /*REFERENCED*/  
  17.       _Lock __lock_instance;  
  18. #     endif  
  19.       _Obj* __RESTRICT __result = *__my_free_list;  
  20.       if (__result == 0)//若自由链表free_list不存在可用的区块,则从内存池中填充自由链表  
  21.         __ret = _S_refill(_S_round_up(__n));  
  22.       else {//若自由链表free_list存在可用区块,调整free_list  
  23.         *__my_free_list = __result -> _M_free_list_link;  
  24.         __ret = __result;  
  25.       }  
  26.     }  
  27.   
  28.     return __ret;  
  29.   };  

空间释放函数deallocate()

    首先判断区块的大小,大于128bytes直接调用第一级配置器,若小于128bytes,则找出相应的自由链表free_list,将其回收。源代码如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1.   /* __p may not be 0 */  
  2.   static void deallocate(void* __p, size_t __n)  
  3.   {  
  4.     if (__n > (size_t) _MAX_BYTES)//内存大于128时,采用第一级配置器处理  
  5.       malloc_alloc::deallocate(__p, __n);  
  6.     else {//否则,找到相应的自由链表位置,将其回收  
  7.       _Obj* __STL_VOLATILE*  __my_free_list  
  8.           = _S_free_list + _S_freelist_index(__n);  
  9.       _Obj* __q = (_Obj*)__p;  
  10.   
  11.       // acquire lock  
  12. #       ifndef _NOTHREADS  
  13.       /*REFERENCED*/  
  14.       _Lock __lock_instance;  
  15. #       endif /* _NOTHREADS */  
  16.       __q -> _M_free_list_link = *__my_free_list;  
  17.       *__my_free_list = __q;  
  18.       // lock is released here  
  19.     }  
  20.   }  

重新填充函数refill()

    重新填充函数refill()是在自由链表不存在可用的区块时被调用。默认是为自由链表申请20个节点,第1个给客户端,剩下19个留给自由链表管理。原代码如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /* Returns an object of size __n, and optionally adds to size __n free list.*/  
  2. /* We assume that __n is properly aligned.                                */  
  3. /* We hold the allocation lock.                                         */  
  4. template <bool __threads, int __inst>  
  5. void*  
  6. __default_alloc_template<__threads, __inst>::_S_refill(size_t __n)  
  7. {  
  8.     int __nobjs = 20;//默认节点数  
  9.     //调用_S_chunk_alloc,从内存池中获得内存空间  
  10.     char* __chunk = _S_chunk_alloc(__n, __nobjs);  
  11.     _Obj* __STL_VOLATILE* __my_free_list;  
  12.     _Obj* __result;  
  13.     _Obj* __current_obj;  
  14.     _Obj* __next_obj;  
  15.     int __i;  
  16.   
  17.     //如果只有一个区块,返回给客户端,自由链表没有接区块管理  
  18.     if (1 == __nobjs) return(__chunk);  
  19.     //调整自由链表free_list,准备管理新节点  
  20.     __my_free_list = _S_free_list + _S_freelist_index(__n);  
  21.   
  22.     /* Build free list in chunk */  
  23.       __result = (_Obj*)__chunk;//这一块返回给客户端  
  24.       //自由链表free_list指向新配置的空间  
  25.       *__my_free_list = __next_obj = (_Obj*)(__chunk + __n);  
  26.       for (__i = 1; ; __i++) {//这里第0个返回给客户端,所以从1开始  
  27.         __current_obj = __next_obj;  
  28.         __next_obj = (_Obj*)((char*)__next_obj + __n);  
  29.         if (__nobjs - 1 == __i) {  
  30.             __current_obj -> _M_free_list_link = 0;  
  31.             break;  
  32.         } else {  
  33.             __current_obj -> _M_free_list_link = __next_obj;  
  34.         }  
  35.       }  
  36.     return(__result);  
  37. }  

内存池管理机制

     chunk_alloc函数具体实现步骤如下:

  1. 内存池剩余空间完全满足20个区块的需求量,则直接获取对应大小的空间。
  2. 内存池剩余空间不能完全满足20个区块的需求量,但是足够供应一个及以上的区块,则获取满足条件的区块个数的空间。
  3. 内存池剩余空间不能满足一个区块的大小,则:

  • 首先判断内存池中是否有残余零头内存空间,如果有则进行回收,将其编入free_list
  • 然后向heap申请空间,补充内存池。
    • heap有足够的空间,空间分配成功。
    • heap空间不足,即malloc()调用失败。则
      • 查找free_list尚有未用区块,调整以进行释放,将其编入内存池。然后递归调用chunk_alloc函数从内存池取空间供free_list备用。
      • 搜寻free_list释放空间也未能解决问题,这时候调用第一级配置器,利用out-of-memory机制尝试解决内存不足问题。

   源代码如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /* We allocate memory in large chunks in order to avoid fragmenting     */  
  2. /* the malloc heap too much.                                            */  
  3. /* We assume that size is properly aligned.                             */  
  4. /* We hold the allocation lock.                                         */  
  5. template <bool __threads, int __inst>  
  6. char*  
  7. __default_alloc_template<__threads, __inst>::_S_chunk_alloc(size_t __size,   
  8.                                                             int& __nobjs)  
  9. {  
  10.     char* __result;  
  11.     size_t __total_bytes = __size * __nobjs;//所需总的内存块  
  12.     size_t __bytes_left = _S_end_free - _S_start_free;//内存池剩余空间  
  13.   
  14.     if (__bytes_left >= __total_bytes) {//若内存池剩余空间满足20个需求,直接分配  
  15.         __result = _S_start_free;  
  16.         _S_start_free += __total_bytes;  
  17.         return(__result);  
  18.     } else if (__bytes_left >= __size) {  
  19.         /*若内存池剩余空间不满足20个需求,但足够满足一个或多个,取出能够满足条件区块的个数*/  
  20.         __nobjs = (int)(__bytes_left/__size);  
  21.         __total_bytes = __size * __nobjs;  
  22.         __result = _S_start_free;  
  23.         _S_start_free += __total_bytes;  
  24.         return(__result);  
  25.     } else {  
  26.         /*内存池剩余空间连一个区块大小都无法提供*/  
  27.         size_t __bytes_to_get =   
  28.       2 * __total_bytes + _S_round_up(_S_heap_size >> 4);  
  29.         // Try to make use of the left-over piece.  
  30.         if (__bytes_left > 0) {  
  31.             /*判断内存池中是否有残余零头内存空间,如果有则进行回收,将其编入free list*/  
  32.             _Obj* __STL_VOLATILE* __my_free_list =  
  33.                         _S_free_list + _S_freelist_index(__bytes_left);  
  34.   
  35.             ((_Obj*)_S_start_free) -> _M_free_list_link = *__my_free_list;  
  36.             *__my_free_list = (_Obj*)_S_start_free;  
  37.         }  
  38.         //配置可用的堆空间,用来补充内存池空间  
  39.         _S_start_free = (char*)malloc(__bytes_to_get);  
  40.         if (0 == _S_start_free) {//若堆空间不足  
  41.             size_t __i;  
  42.             _Obj* __STL_VOLATILE* __my_free_list;  
  43.         _Obj* __p;  
  44.             // Try to make do with what we have.  That can't  
  45.             // hurt.  We do not try smaller requests, since that tends  
  46.             // to result in disaster on multi-process machines.  
  47.             for (__i = __size;  
  48.                  __i <= (size_t) _MAX_BYTES;  
  49.                  __i += (size_t) _ALIGN) {  
  50.     /*搜寻适当的free list(适当的是指:尚有未用区块,并且区块足够大),调整以进行释放,将其编入内存池。 
  51.                      **然后递归调用chunk_alloc函数从内存池取空间供free list。*/  
  52.                 __my_free_list = _S_free_list + _S_freelist_index(__i);  
  53.                 __p = *__my_free_list;  
  54.                 if (0 != __p) {//自由练表中存在未被使用的区块,调整并释放该区块  
  55.                     *__my_free_list = __p -> _M_free_list_link;  
  56.                     _S_start_free = (char*)__p;  
  57.                     _S_end_free = _S_start_free + __i;  
  58.                     return(_S_chunk_alloc(__size, __nobjs));  
  59.                     // Any leftover piece will eventually make it to the  
  60.                     // right free list.  
  61.                 }  
  62.             }  
  63.         _S_end_free = 0;    // In case of exception.调用第一级配置器  
  64.             _S_start_free = (char*)malloc_alloc::allocate(__bytes_to_get);  
  65.             // This should either throw an  
  66.             // exception or remedy the situation.  Thus we assume it  
  67.             // succeeded.  
  68.         }  
  69.         _S_heap_size += __bytes_to_get;  
  70.         _S_end_free = _S_start_free + __bytes_to_get;  
  71.         return(_S_chunk_alloc(__size, __nobjs));  
  72.     }  
  73. }  

多线程环境下内存池互斥访问

    在第二级配置器中,存在着多线程环境的内存池管理,解决多线程环境下内存池互斥访问,需在自由链表 free_list 中进行修改调整,我们从 SGI STL 第二级配置器源码中看到,嵌套一个类class _Lock ,该类的作用是解决互斥访问,并且只有两个函数:构造函数和析构函数;使用构造函数对内存池进行加锁,使用析构函数对内存池进行解锁。关于多线程内存池互斥访问的源代码如下:
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #ifdef __STL_THREADS  
  2. # include <stl_threads.h>//包含线程文件  
  3. # define __NODE_ALLOCATOR_THREADS true  
  4. # ifdef __STL_SGI_THREADS  
  5.   // We test whether threads are in use before locking.  
  6.   // Perhaps this should be moved into stl_threads.h, but that  
  7.   // probably makes it harder to avoid the procedure call when  
  8.   // it isn't needed.  
  9.     extern "C" {  
  10.       extern int __us_rsthread_malloc;  
  11.     }  
  12.     // The above is copied from malloc.h.  Including <malloc.h>  
  13.     // would be cleaner but fails with certain levels of standard  
  14.     // conformance.  
  15. #   define __NODE_ALLOCATOR_LOCK if (threads && __us_rsthread_malloc) \  
  16.                 { _S_node_allocator_lock._M_acquire_lock(); }  
  17. #   define __NODE_ALLOCATOR_UNLOCK if (threads && __us_rsthread_malloc) \  
  18.                 { _S_node_allocator_lock._M_release_lock(); }  
  19. # else /* !__STL_SGI_THREADS */  
  20. #   define __NODE_ALLOCATOR_LOCK \  
  21.         { if (threads) _S_node_allocator_lock._M_acquire_lock(); }//获取锁  
  22. #   define __NODE_ALLOCATOR_UNLOCK \  
  23.         { if (threads) _S_node_allocator_lock._M_release_lock(); }//释放锁  
  24. # endif  
  25. #else  
  26. //  Thread-unsafe  
  27. #   define __NODE_ALLOCATOR_LOCK  
  28. #   define __NODE_ALLOCATOR_UNLOCK  
  29. #   define __NODE_ALLOCATOR_THREADS false  
  30. #endif  
  31.   
  32. # ifdef __STL_THREADS  
  33.     static _STL_mutex_lock _S_node_allocator_lock;//互斥锁变量  
  34. # endif  
  35.   
  36.     // It would be nice to use _STL_auto_lock here.  But we  
  37.     // don't need the NULL check.  And we do need a test whether  
  38.     // threads have actually been started.  
  39.     class _Lock;  
  40.     friend class _Lock;  
  41.     class _Lock {//解决内存池在多线程环境下的管理  
  42.         public:  
  43.             _Lock() { __NODE_ALLOCATOR_LOCK; }  
  44.             ~_Lock() { __NODE_ALLOCATOR_UNLOCK; }  
  45.     };  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值