ACE的实现上,自己的内存分配器记录了分配的地址空间起始地址和长度,ACE_Based_Pointer_Basic<T>在构造的时候会根据自己的地址判断自己需要计算的起始地址是什么。而且在封装上考虑比较舒服。但需要提醒的是,你需要记录的地址必须仍然是这块共享内存上的,否则……(不解释)。
而且要说明的是ACE的自有容器虽然也支持使用共享内存的分配器,但由于ACE容器的内部也有大量的指针,而不是记录相对地址,所以ACE的容器其实也不能在共享内存中。所以ACE的学术气息更加浓烈一点,实用性并不高(ACE的容器本身也不好用)。所以可以说,ACE踹开了那扇门,但并没有进入这个殿堂。
5 BOOST的interprocess容器内存分配器这几年BOOST开始流行,BOOST的interprocess库中一个在共享内存容器内存分配器的实现,但要注意其配合使用容器vector,list,是BOOST自己的container容器。这个分配器并不能和现有大部分STL实现配合使用。
可以说其实BOOST的实现和ACE的思路是类似的,方法也是分配一个块共享内存,为这块共享内存生成一个容器内存分配器,这个分配器为这个容器服务,使用共享内存容器分配器后,容器内部所有的地址记录相对地址,而不是绝对地址。
template <class PointedType, class DifferenceType, class OffsetType, std::size_t OffsetAlignment> class offset_ptr
对比ACE,BOOST实现的不同,一方面BOOST的共享内存管理和容器内存分配器的思路很清晰,整体设计思路还是在STL的体系之下,ACE诞生的年代过早,容器整体体系和STL完全不相容,另外一方面,BOOST在相对地址的处理上也简单一点。他只记录offset_ptr对象的this地址到需要记录的地址之间的长度。
另外,BOOST代码虽然条理上和STL容器一致,但BOOST的代码阅读难度至少double于STLPort,传统调试跟踪代码的方式单步跟踪虽然有效,但是很多变量都无法查询到实际值,宏满天飞。期待剖析BOOST代码的大神出现。
6 共享内存的容量而且另外一个小问题是,我们申请的共享内存的大小都是有一个大小限度的,而STL容器往往有随需增长的特点,而这个特点和共享内存其实也有一些不调和性。
ACE的问题在这个问题上给出过一些学术解,依靠信号,异常等方式,给你机会自己扩展内存,但估计也就限于学术探讨范围。
BOOST在这个问题上更加明了,当内存不够分配的时候抛出bad_alloc异常。反而更加清晰一点。
7 另外一种解思考,固定最大长度的容器BOOST的实现固然不错,但也有几个并不那么完美的地方,而且当时可以参考的思路还没有这样多,(我自己实现自己容器的时候是2005年,BOOST的interprocess的库在08年才出现)
第一,放入N个T类型的数据的容器到底需要多大共享内存?因为容器本身是有消耗,而这点BOOST并没有接口告诉我。对于使用共享内存的容器,我们都知道我们需要使用的最大数量是多少。
第二,如果最大的尺寸我们已经知道。那么其实我们对于所有的可以在一开始就分配好空间,而不是在每次push_back的时候调用alloctor去分配地址,其实alloctor内部仍然使用了红黑树去管理所有的分配地址,坦白说麻烦。而且由于最大尺寸固定,我们所有的数据的内部位置关系都可以采用数组下标定位。这样也就一样省去了指针的麻烦。
综合上面的考虑。我们当时的设计思路大致是,根据你传入的参数判定告知调用者所需的内存大小,调用者自己分配好内存(可以是共享内存),根据分配的内存地址构造一个容器,容器的操作和模板基本一致,也提供迭代器等方法等方法访问,容器的内部结构如下图。
这个方法和STL容器的语法基本兼容,性能比BOOST的那个速度应该要快一点(不用在每次都alloc一个node节点)。寸有所长,尺有所短,这也算一个思路把。
具体的代码以后估计会开源。
8 总结在共享内存中使用模板容器的关键问题是指针的问题,相对地址是解决这���问题比较好的方法。一个比较通用的方案是将所有的指针改成一个相对地址记录,还有一种思路对于容器的处理方式是将容器的所有数据按最大数量分配好,使用下标处理。
9 参考文档《STL源码剖析》 侯捷
《ACE程序员指南》 马维达
------------------------------分割线------------------------------
C++ Primer Plus 第6版 中文版 清晰有书签PDF+源代码
将C语言梳理一下,分布在以下10个章节中:
Linux-C成长之路(十):其他高级议题