__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的作用不大清楚,因爲沒找到使用它的地方。

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