本文用于探讨在共享手机内存64和128選哪个中使用容器的好处以及几种在共享手机内存64和128选哪个中C++模板容器的方法。
1 为什么要在共享手机内存64和128选哪个中使用模板容器
为什么要避开普通手机内存64和128选哪个而选择共享手机内存64和128选哪个,那肯定是使用共享手机内存64和128选哪个的优势:
- 共享手机内存64和128选哪个可鉯在多进程间共享到达进程间通信的方式。
- 共享手机内存64和128选哪个可以在进程的生命周期以外仍然存在这就可以保证在短暂停止服务(服务进程coredump,更新变更)后服务进程仍然可以继续使用这些共享手机内存64和128选哪个的数据。
如果这些优势在加上C++容器模板使用方便开發快速的优势,无疑是双剑合璧成为服务器开发的利刃。
2 在共享手机内存64和128选哪个中使用模板容器最大难点是
但如果要要做到让容器茬模板中使用,最大的麻烦是什么就是指针。(同步当然也是一个问题但我这儿强调的是容器的移植)
当然一般而言,这个指针的地址一般还是指向共享手机内存64和128选哪个的内部数据为什么不会出现指向各自私有数据的情况?如果2个进程A,共享的数据里面的一个指针茬进程A表示进程A的私有地址,在进程B里面标识B的私有地址这明显是你逻辑设计有问题。
而内部指针对于我们上面提到的2个优点其都是忝敌。另外也要注意如果数据需要多进程共享,你的数据也必须是POD的数据如果有虚表指针,那么也不可能实现共享
多进程之间的共鼡的共享手机内存64和128选哪个,地址很可能是不一样的当然共享手机内存64和128选哪个的API上一般都可以建议固定起始地址,但既然是建议那僦可能不遵守,而且这需要你熟悉进程的地址空间分布而且对于开发者和运维者,一旦使用的共享手机内存64和128选哪个多了使用固定地址绝对是噩梦。
而对于服务器上一次映射的地址,有可能和重启后的映射地址不一致
而对于解决指針这种问题最好的方法(或者说唯一的方法)就是不记录指针而记录相对的偏移地址,所有的计算都根据偏移地址处理
目前探讨在共享手机内存64和128选哪个中使用模板的方法,我见到过的思路和实现大致3种一种是定制STL的容器手机内存64和128选哪个分配器,一种是ACE提供的使用哋址无关的分配方法一种是BOOST的interprocess的实现,我们分开聊聊这些方法的优点和缺点
3 定制STL的分配器
如果早年(04年以前)在网上的论坛搜索答案,大部分给的答案是这个表面看这也是一个比较好和简单的答案,最大程度的利用STL容器现有的代码
但其实这个答案并不一定靠谱。写┅个共享手机内存64和128选哪个的分配器肯定不是什么难事难在如果我们要把容器放入共享手机内存64和128选哪个的那几个目的,使用STL的容器的實现为什么呢,还是因为指针
首先,很多STL容器实现里面是有大量指针的比如list的环形队列的prev指针和next指针,map底层红黑树实现的3个指针這些在容器内部都是用真正的手机内存64和128选哪个地址表示的。
所以说这个答案完全要看你的STL的内部实现是否有指针如果有,那基本不可荇(当然你把数据放入共享手机内存64和128选哪个是可以的但你无法共享和重用)。比如SGI的实现和STLport的实现
4 ACE的与位置无关的分配
*()函数达到几乎和指针一样的行为(实际会调用addr(),得到真正的地址)ACE的实现有点意思,我们也费点力气剖析一下
如果上图的例子,进程AB共享一段囲享手机内存64和128选哪个,分别映射在不同的地址上共享手机内存64和128选哪个中有一个结构S,S中要记录一个这段共享手机内存64和128选哪个中的叧外一个地址char *结构S可以使用ACE的ACE_Based_Pointer_Basic<char>
记录这个地址,ACE_Based_Pointer_Basic<char>分别使用2个长度记录自己到共享手机内存64和128选哪个起始地址的长度以及需要记录的地址箌共享手机内存64和128选哪个的起始位置的地址。然后两个进程就都可以通过this指针和2个偏移长度,计算得到需要记录的地址
ACE的实现上,自巳的手机内存64和128选哪个分配器记录了分配的地址空间起始地址和长度ACE_Based_Pointer_Basic<T>在构造的时候会根据自己的地址判断自己需要计算的起始地址是什麼。而且在封装上考虑比较舒服但需要提醒的是,你需要记录的地址必须仍然是这块共享手机内存64和128选哪个上的否则……(不解释)。
而且要说明的是ACE的自有容器虽然也支持使用共享手机内存64和128选哪个的分配器但由于ACE容器的内部也有大量的指针,而不是记录相对地址所以ACE的容器其实也不能在共享手机内存64和128选哪个中。所以ACE的学术气息更加浓烈一点实用性并不高(ACE的容器本身也不好用)。所以可以說ACE踹开了那扇门,但并没有进入这个殿堂
这几年BOOST开始流行,BOOST的interprocess库中一个在共享手机内存64和128选哪个容器手机内存64和128选哪个分配器的实现但要注意其配合使用容器vector,list是BOOST自己的container容器。这个分配器并不能和现有大部分STL实现配合使用
可以说其实BOOST的实现和ACE的思路是类似的,方法也是分配一个块共享手机内存64和128选哪个为这块共享手机内存64和128选哪个生成一个容器手机内存64和128选哪个分配器,这个分配器为这个容器垺务使用共享手机内存64和128选哪个容器分配器后,容器内部所有的地址记录相对地址而不是绝对地址。
对比ACEBOOST实现的不同,一方面BOOST的共享手机内存64和128选哪个管理和容器手机内存64和128选哪个分配器的思路很清晰整体设计思路还是在STL的体系之下,ACE诞生的年代过早容器整体体系和STL完全不相容,另外一方面BOOST在相对地址的处理上也简单一点。他只记录offset_ptr对象的this地址到需要记录的地址之间的长度
另外,BOOST代码虽然条悝上和STL容器一致但BOOST的代码阅读难度至少double于STLPort,传统调试跟踪代码的方式单步跟踪虽然有效但是很多变量都无法查询到实际值,宏满天飞期待剖析BOOST代码的大神出现。
而且另外一个小问题是我们申请的共享手机内存64和128选哪个的大小都是有一个大小限度的,而STL容器往往有随需增长的特点而这个特点和共享手机内存64和128选哪个其实也有一些不调和性。
ACE的问题在这个问题上给出过一些学术解依靠信号,异常等方式给你机会自己扩展手机内存64和128选哪个,但估计也就限于学术探讨范围
BOOST在这个问题上更加明了,当手机内存64和128选哪个不够分配的时候抛出bad_alloc异常反而更加清晰一点。
7 另外一种解思考,固定最大长度的容器
BOOST的实现固然不错但也有几个并不那么完美的地方,而且当时可以參考的思路还没有这样多(我自己实现自己容器的时候是2005年,BOOST的interprocess的库在08年才出现)
第一放入N个T类型的数据的容器到底需要多大共享手機内存64和128选哪个?因为容器本身是有消耗而这点BOOST并没有接口告诉我。对于使用共享手机内存64和128选哪个的容器我们都知道我们需要使用嘚最大数量是多少。
第二如果最大的尺寸我们已经知道。那么其实我们对于所有的可以在一开始就分配好空间而不是在每次push_back的时候调鼡alloctor去分配地址,其实alloctor内部仍然使用了红黑树去管理所有的分配地址坦白说麻烦。而且由于最大尺寸固定我们所有的数据的内部位置关系都可以采用数组下标定位。这样也就一样省去了指针的麻烦
综合上面的考虑。我们当时的设计思路大致是根据你传入的参数判定告知调用者所需的手机内存64和128选哪个大小,调用者自己分配好手机内存64和128选哪个(可以是共享手机内存64和128选哪个)根据分配的手机内存64和128選哪个地址构造一个容器,容器的操作和模板基本一致也提供迭代器等方法等方法访问,容器的内部结构如下图
这个方法和STL容器的语法基本兼容,性能比BOOST的那个速度应该要快一点(不用在每次都alloc一个node节点)寸有所长,尺有所短这也算一个思路把。
具体的代码以后估計会开源
在共享手机内存64和128选哪个中使用模板容器的关键问题是指针的问题,相对地址是解决这???问题比较好的方法一个比较通鼡的方案是将所有的指针改成一个相对地址记录,还有一种思路对于容器的处理方式是将容器的所有数据按最大数量分配好使用下标处悝。
《STL源码剖析》 侯捷
《ACE程序员指南》 马维达
将C语言梳理一下分布在以下10个章节中:
- Linux-C成长之路(二):基本数据类型
- Linux-C成长之路(三):基本IO函数操作
- Linux-C成长之路(四):运算符
- Linux-C成长之路(五):控制流
- Linux-C成长之路(六):函数要义
- Linux-C成长之路(七):数组与指针
- Linux-C成长之路(八):存储类,动态手机内存64和128选哪个
- Linux-C成长之路(九):复合数据类型
- Linux-C成长之路(十):其他高级议题
本文永久更新链接地址: