time 
设为首页】【收藏本站
当前位置: 主页 > 程序设计 > C\C++\VC > C++基础 > ACE学习4 ACE_Data_Block的学习

ACE学习4 ACE_Data_Block的学习

时间:2010-04-16 23:19 点击:1713次 字体:[ ]




ACE_Data_Block 学习

ACE_Data_Block是ACE中很重要的类, 是对原始buffer的最基础封装

    啥是ACE_Data_Block? ACE_Data_Block都有啥用? ACE_Data_Block怎么用? ACE_Data_Block底层是咋实现的? 通过源代码能很好的了解这些信息

 

类成员变量

      ACE_Message_Type type_ 指示数据的类型

      size_t cur_size_                数据的当前大小

      size_t max_size_              最大容量

      Message_Flags flags_        有用的标志

      char* base_                     真正的原始buffer

      ACE_Allocator *allocator_strategy_  内存分配策略, 这个是用来分配原始buff的

      ACE_Lock *locking_strategy_ 锁策略

      int reference_count_          引用计数

      ACE_Allocator *data_block_allocator_ 用来分配ACE_Data_Block, 比如复制一份自己, 这个用了replacement new手法

      注意注意, 没有wptr, rptr

      说明ACE_Data_Block的职责是:

             [管理buffer自己本身]原始buffer的一个wrapper, 为原始buffer提供一个分配, 复制, 引用计数生命周期的管理

      ACE_Data_Block的职责不是:

             [提供使用buffer接口] 智能buffer, 环形buffer

 

重要的成员函数

      1.  最重要的是构造函数

      ACE_Data_Block::ACE_Data_Block (size_t size,                                    // buffer大小
                                ACE_Message_Block::ACE_Message_Type msg_type,  // 数据类型
                                const char *msg_data,                                             // 原始buffer
                                ACE_Allocator *allocator_strategy,                             // 内存分配策略
                                ACE_Lock *locking_strategy,                                     // 锁策略
                                ACE_Message_Block::Message_Flags flags,                 // 有用的标志位
                                ACE_Allocator *data_block_allocator)                         // ACE_Data_Block自身的内存分配策略

      从构造函数可以看出, ACE_Data_Block是一个比较简单的类, 构造函数的参数基本上和成员变量是一一对应的, 要说明的是

          1. allocator_strategy和data_block_allocator都可以为空, 那么他们会被初始化为ACE_Allocator::instance()

          2. msg_data可以为空值, 那么就会调用allocator_strategy->malloc(size)分配内存

          3. 构造完成后 cur_size_ = max_size_ = size

      这其中的1, 2非常重要, 因为它们涉及到了内存分配策略和内存分配, 思考一下, ACE_Data_Block的设计初衷是什么? 那就是"提供引用计数, 减少不必要的数据拷贝", 这一点在实际的应用中是非常重要的, 再想想服务器的内存使用策略要点:

          1. 尽可能少的数据拷贝

          2. 尽可能少的内存分配操作

      这里, ACE_Data_Block通过使用引用计数的方式, 达到了第一个目标, 但是, 内存分配策略它是管不了的, 是用户进行配置的, 如果在服务器端大量的使用ACE_Data_Block, 而且每次msg_data都传null[要分配内存], 这样就会造成大量的内存分配操作. 其实从构造函数可以看出, ACE_Data_Block并没有给出内存分配策略默认参数为null, 或许也是为了不让平凡内存分配策略成为默认行为吧~~~也可能是我在YY, 但是肯定的一点是平凡内存分配策略是有问题的, 会造成大量的内存分配操作, 这里, allocator_strategy和data_block_allocator或许都可以配置成为内存池或别的更好的内存分配策略

       还有一点值得说明的是flags标志位, 如果设置了DONT_DELETE标志, 那么表明ACE_Data_Block在放弃对当前底层buffer管理权限时, 不去释放底层buffer, 否者就要调用allocator_strategy_->free (base_)操作, 注意, 这个地方很危险, 它在提供灵活性的时候极大的增大的错误的发生概率, 这里会因为标志位的设置失误, 引起忘记释放内存导致内存泄露, 或者释放了不该释放的内存或不能释放的内存

 

       2. ACE_Data_Block::base (char *msg_data,
                      size_t msg_length,
                      ACE_Message_Block::Message_Flags msg_flags)

       比较简单, 安装底层buffer, 这里可能导致原底层buffer的释放, 试原flag设置而定

 

       3. ACE_Data_Block * ACE_Data_Block::clone (ACE_Message_Block::Message_Flags mask)

       获得一份ACE_Data_Block 的拷贝, 注意

               1. 先调用data_block_allocator分配内存, 构造一个新的ACE_Data_Block    [分配内存 for ACE_Data_Block]

               2. 底层buffer也会分配内存                                                                [分配内存 for raw_buffer]

               3. 拷贝原底层buffer数据到新的底层buffer

       结束后, 获得一份全新的, 一样的~~~   ACE_Data_Block, 从里到外, 但是这里面的内存分配, 数据拷贝....要慎重使用

 

       4. ACE_Data_Block *ACE_Data_Block::duplicate (void)

       only增加引用计数, very good!

 

       5. ACE_Data_Block *release (ACE_Lock *lock = 0)

       引用计数减1, 若引用计数为0, 会删除ACE_Data_Block自己并返回0, 这将引发ACE_Data_Block析构函数的调用, 否则返回this

 

       6. ACE_Data_Block::~ACE_Data_Block

       在析构函数中, 有一句断言(this->reference_count_ <= 1), 原因很明显, 如果多于一个人在使用这个data_block, 删除该data_block就是一个不正确行为, 这里要注意的是, 这只是一个断言~~~~~

       在析构函数中, 如果_flag没有置位DONT_DELETE, 那么要释放底层被管理的buffer~~

 

       总结

       1. 重新认识构造函数参数的意义, 其他的啥也不说捏~~~看懂构造函数的参数啥都明白了

          ACE_Data_Block::ACE_Data_Block (size_t size,                                // 被委托管理的底层原始buffer的大小
                                ACE_Message_Block::ACE_Message_Type msg_type,  // 数据类型
                                const char *msg_data,                                             // 被委托管理的底层原始buffer
                                ACE_Allocator *allocator_strategy,                             // 底层原始buffer内存分配策略[可传内存池避免内存分配平凡调用, ace中就有好多可用]
                                ACE_Lock *locking_strategy,                                     // 锁策略
                                ACE_Message_Block::Message_Flags flags,                 // 有用的标志位, DONT_DELETE用来指定ACE_Data_Block在合适时间是否负责释放被委托管理的底层原始buffer
                                ACE_Allocator *data_block_allocator)                         // ACE_Data_Block自身的内存分配策略[可传内存池避免内存分配平凡调用]

       2. 总结ACE_Data_Block的作用

           1. 管理原始buffer的生命周期[原始buffer外面传进来]

           2. 提供并管理原始buffer的生命周期[原始buffer内部申请出来]

       3. 学习经验

           ACE_Data_Block看上去是个很简单的类, 但是就是这种简单, 是很难学习的, 在我自己写代码的时候, 如果让我写个buffer管理的类, 我肯定是把引用计数, 读写接口, XXXX都去放在同一个类中, 但是, 这样其实是违反了"类单一职责"的设计原则的, ACE从总体上看是非常复杂的, 但是单看其中的每一部分的话, 是很清晰和目的明确的, 很喜欢, 我想, 看它的代码, 学习这些设计原则在实际中的应用, 才是最重要的



本文地址 : http://www.fengfly.com/plus/view-173328-1.html
标签: ACE ACE_Data_Block
------分隔线----------------------------
最新评论 查看所有评论
发表评论 查看所有评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
验证码: