__mt_alloc源码分析(6)

class __pool<true>

__pool<true>是多线程下的内存池类型。在某些方面,它是__pool<false>的扩展,但是在其他很多方面,它比__pool<false>要复杂得多。__pool<true>的基类也是__pool_base,所以它继承了__pool_base的所有成员变量,包括_M_options_M_binmap_M_init。同时__pool_base::_Tune__pool_base::_Block_address类型也是从__pool_base继承而来。

 

257  #ifdef __GTHREADS

 

所有__pool<true>的代码都包裹在这个条件宏里,所以如果你的程序没有支持多线程,__pool<true>就不会存在。

 

258    /// Specialization for thread enabled, via gthreads.h.

259    template<>

260      class __pool<true> : public __pool_base

261      {

262      public:

263        // Each requesting thread is assigned an id ranging from 1 to

264        // _S_max_threads. Thread id 0 is used as a global memory pool.

265        // In order to get constant performance on the thread assignment

266        // routine, we keep a list of free ids. When a thread first

267        // requests memory we remove the first record in this list and

268        // stores the address in a __gthread_key. When initializing the

269        // __gthread_key we specify a destructor. When this destructor

270        // (i.e. the thread dies) is called, we return the thread id to

271        // the front of this list.

 

这段注释描述了_Thread_record的作用:给线程分配id。详细的内容会在后面研究到。

 

272        struct _Thread_record

273        {

274     // Points to next free thread id record. NULL if last record in list.

275     _Thread_record* volatile        _M_next;

276    

277     // Thread id ranging from 1 to _S_max_threads.

278     size_t                          _M_id;

279        };

 

__pool<true>里存在一个由_Thread_record对象组成的链表,它们的_M_id成员会分别初始化为12..._S_max_threads,所以每个_Thread_record对象代表了一个线程id。当某线程第一次向__mt_alloc申请内存时,__pool<true>从这个链表里拿出一个_Thread_record对象,分配给该线程,于是这个线程的id就是_Thread_record对象的_M_id成员值。当这个线程退出的时候,__pool<true>会回收_Thread_record对象,这样就可以把这个id重新分配给其他线程。

 

281        union _Block_record

282        {

283     // Points to the block_record of the next free block.

284     _Block_record* volatile         _M_next;

285    

286     // The thread id of the thread which has requested this block.

287     size_t                          _M_thread_id;

288        };

 

前面研究过,联合结构体_Block_record是空闲内存块的头信息。对比一下__pool<false>::_Block_record的定义,可以发现这里多了一个_M_thread_id,其实它才是_Block_record真正需要“保存”的信息。分配给用户使用的内存块,会把执行“分配”操作的线程的id存放在_M_thread_id里,由于内存块可能在线程之间“传递”,最后执行“释放”操作的不一定是原来的那个线程,所以只能通过_M_thread_id来知道这些信息。

 

290        struct _Bin_record

291        {

292     // An "array" of pointers to the first free block for each

293     // thread id. Memory to this "array" is allocated in

294     // _S_initialize() for _S_max_threads + global pool 0.

295     _Block_record** volatile        _M_first;

296    

297     // A list of the initial addresses of all allocated blocks.

298     _Block_address*              _M_address;

 

2个成员变量的意义和__pool<false>::_Bin_record里的是一样的。

 

300     // An "array" of counters used to keep track of the amount of

301     // blocks that are on the freelist/used for each thread id.

302     // Memory to these "arrays" is allocated in _S_initialize() for

303     // _S_max_threads + global pool 0.

304     size_t* volatile                _M_free;

305     size_t* volatile                _M_used;

 

这是2个计数器数组,分别记录每个线程id对应的空闲内存块和正在使用内存块的个数。也许读者还记得,__mt_alloc会在一定条件下把某个线程的空闲内存块归还给全局的空闲块链表,这个条件就是由线程的usedfree计数器决定的。

 

307     // Each bin has its own mutex which is used to ensure data

308     // integrity while changing "ownership" on a block.  The mutex

309     // is initialized in _S_initialize().

310     __gthread_mutex_t*              _M_mutex;

 

每当涉及到多线程间操作bin的内部成员时,都会进行加锁与解锁操作。

 

311        };

 

__pool<true>成员变

__pool<true>有一部分成员变量是从基类__pool_base继承而来,在研究__pool<false>的时候已经介绍过它们了。这里主要看看__pool<true>自己的成员变量。

366        // An "array" of bin_records each of which represents a specific

367        // power of 2 size. Memory to this "array" is allocated in

368        // _M_initialize().

369        _Bin_record* volatile _M_bin;

370 

371        // Actual value calculated in _M_initialize().

372        size_t                      _M_bin_size;

 

2个成员的意义和__pool<true>里的一样,无需介绍。

 

374        _Thread_record*       _M_thread_freelist;

375        void*         _M_thread_freelist_initial;

 

_M_thread_freelist是前面说过的未分配线程id的链表。_M_thread_freelist_initial的作用不大清楚,因为没找到使用它的地方。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章