__mt_alloc源码分析(9)
来源:互联网 发布:mac安装office教程 编辑:程序博客网 时间:2024/06/06 02:57
__pool<true>的内存分配
虽然我在前面已经介绍过__mt_alloc::allocate函数,但是结合这里的多线程环境,我建议读者还是回顾一下它的代码。其实__mt_alloc::allocate函数并不关心内存池是多线程还是单线程的,它在2种环境下都采用统一的操作步骤,只是在单线程的时候其中有些步骤什么事情都不用做,于是我们前面就忽略了。而到了多线程下,每个步骤都变得有用和必需了。
__pool<true>::_M_get_thread_id
首先我们遇到的多线程下内存池重要的操作步骤,是获得线程的id。
<mt_allocator.cc>
581 size_t
582 __pool<true>::_M_get_thread_id()
函数原型,返回值就是调用_M_get_thread_id函数的线程id。
583 {
584 // If we have thread support and it's active we check the thread
585 // key value and return its id or if it's not set we take the
586 // first record from _M_thread_freelist and sets the key and
587 // returns it's id.
588 if (__gthread_active_p())
检查是否链接了多线程库,如果没有的话,会当成单线程环境处理。
589 {
590 void* v = __gthread_getspecific(__gnu_internal::freelist._M_key);
591 size_t _M_id = (size_t)v;
访问线程私有数据,并转化成size_t类型的线程id。前面已经研究过,符号__gthread_getspecific是POSIX多线程库函数pthread_getspecific的弱引用,而后者的作用也在介绍freelist的时候也研究过了。
592 if (_M_id == 0)
如果得到的线程id为0,说明从未给这个线程分配过id,那么开始id分配工作。
593 {
594 {
这个“{”括号是用来限定下面__gnu_cxx::lock的锁定范围的,和前面介绍_M_initialize时的那个括号一样。
595 __gnu_cxx::lock sentry(__gnu_internal::freelist_mutex);
596 if (__gnu_internal::freelist._M_thread_freelist)
检查是否有空闲的线程id。
597 {
598 _M_id = __gnu_internal::freelist._M_thread_freelist->_M_id;
599 __gnu_internal::freelist._M_thread_freelist
600 = __gnu_internal::freelist._M_thread_freelist->_M_next;
得到头一个节点的线程id,然后把这个节点移出freelist。虽然这里再没有任何指针指向这个移出的节点,但是程序并没有内存泄漏,因为freelist._M_thread_freelist_array指向了整个节点数组,而且我们还可以通过线程id找到对应的节点。
601 }
602 }
603
604 __gthread_setspecific(__gnu_internal::freelist._M_key,
605 (void*)_M_id);
既然这个线程分配到了一个id,那么把它设置到线程私有数据里,这样以后就可以直接获得它了。有一个问题就是,如果线程id链表为空,没有获到线程id会怎样?那么这时候_M_id的值应该是0,于是整个_M_get_thread_id函数就会返回0。读者可以思考一下事情会变成怎样。
606 }
607 return _M_id >= _M_options._M_max_threads ? 0 : _M_id;
返回线程id。注意到这里作了比较,如果线程id超过了规定的线程个数上限,就返回0。我觉得这属于程序的策略,不同的人会有不同的意见。比如我初始化__mt_alloc<int>只支持10个线程,而其他类型不限制(默认是4096个),那么当有第11个线程要分配int对象的时候,我想让__mt_alloc<int>怎么做?有的人会认为,既然线程id有4096个,为什么不忽略用户的“错误设置”,让__mt_alloc<int>正确工作呢?而另一部分人则会持相反看法,认为用户既然设置了这个参数,就不能被忽略。
显然__mt_alloc的作者同意后一部分人的想法,忠实的遵守用户的设置,即使是程序崩溃了,也要让用户来选择是对是错。
608 }
609
610 // Otherwise (no thread support or inactive) all requests are
611 // served from the global pool 0.
612 return 0;
如果程序不支持多线程,直接返回0。
613 }
__pool<true>::_M_adjust_freelist
得到了线程id,__mt_alloc::allocate会在对应bin下对应的_M_first链表里,找寻空闲块,找到之后会交给用户使用,不过交出去之前还需要调整一些设置工作,这些工作是交给_M_adjust_freelist来做的。
337 void
338 _M_adjust_freelist(const _Bin_record& __bin, _Block_record* __block,
339 size_t __thread_id)
340 {
341 if (__gthread_active_p())
检查是否支持多线程,因为在单线程下这个函数什么事情也不需要做。
342 {
343 __block->_M_thread_id = __thread_id;
设置分配出去的块的头信息,主要是记录下分配线程的id。这是因为,如果块被传递给了其他线程,并由另一个线程释放的话,__pool<true>仍需要将分配线程的used计数器减1。
344 --__bin._M_free[__thread_id];
345 ++__bin._M_used[__thread_id];
调整分配线程的used和free计数器。
346 }
347 }
- __mt_alloc源码分析(9)
- __mt_alloc源码分析(1)
- __mt_alloc源码分析(2)
- __mt_alloc源码分析(3)
- __mt_alloc源码分析(4)
- __mt_alloc源码分析(5)
- __mt_alloc源码分析(6)
- __mt_alloc源码分析(7)
- __mt_alloc源码分析(8)
- __mt_alloc源码分析(10)
- __mt_alloc源码分析(11)
- __mt_alloc源码分析(12)
- 9 (phonegap源码分析)代码附录
- Mahout贝叶斯算法源码分析(9)
- Zookeeper源码分析(9)- ToBeAppliedRequestProcessor
- HDFS源码分析(9):DFSCliet
- java源码分析(9)-Byte
- Leveldb源码分析--9
- oracle中常用的sql查询语句
- 利用工作流引擎技术设计应用系统的思路
- Java程序员:一刻钟精通正则表达式
- TreeView控件时发现带有CheckBox控件的TreeNode对象(TreeView节点),选择CheckBox无法回发页面
- 没有电子商务,企业只能等待死亡
- __mt_alloc源码分析(9)
- HP 出现NO PRINT CARTRIDGE
- ASP.NET 运行状况监视
- USACO 3.2 Magic Squares (msquares) 题解
- 如何对存储过程返回的结果进行条件查询
- 关于dbnull的用法
- XLINQ Introduction Part 3 Of 3 By Sacha Barber(Refer from codeproject)
- C#发现之旅第五讲 图形开发基础篇
- C#中的DBNull、Null和String.Empty解释