以前看了ace_reactor的相关文章, 也自己动手敲过reactor的小的demo, 难得一见的在mangos的更新中也看见了实际使用ace_reactor~~~但是总是感觉ace_reactor的实现对自己来说没有更清晰的认识, 由于性格问题, 必须看看究竟是怎样的才能满意, 所以打算在这里记录一下分析的过程, 以备以后使用或者复习~~~
要求的英语<;虚拟机的设计与实现>作者就说了, 如果你在了解一个系统时能够有一个系统的总体结构图, 你会觉得这是非常幸运的一件事情. 所以, 在当前环境下(网上有很多关于reactor的分析, 讲解的情况)分析实现的时候, 很容易就能找到一个ace_reactor的总体结构图(图1), 图上的各个组件及其关系已经很清楚的表达了reactor的结构, 下面就是最最重要的一点, 在看代码的时候, 随时把reactor的结构表达出的含义记在心里, 不要陷入代码细节泥潭中去, 切记, 呵呵, 其实这句话是对我自己说的. ok, 下面就开始实际的分析了, 第一件事就是定出分析的流程, 这点很重要, 不少时候分析实现坚持不下来就是没有提前定好一个流程, 导致看代码没有方向, 陷入细节中, 最后觉得烦而放弃了, 所以提前有一个计划是不错的, 就按计划按步就班的走就行了.
流程和计划:
1. 分析reactor.h 按功能整理API, "分而治之"的解决方法. (其实它不好看, 就是因为里面东西太多, 而且都合在一起, 形成了胖类~~~我不知道这好不好, 但是感觉很不好, 网上也有人讨论过这件事, 大家可以自己google一下)
2. 将功能作为研究它的最小单位, 以研究功能是如何实现和组织在一起为目标. 这一步要时刻小心进入细节陷阱.
3. 对照图1, 看看这个功能又是如何组合合作的, 功能之间的相互作用和影响, 从总体上理解reactor模式, 总结key word
4. 获取其他reactor系统进行快速的分析
上面就是主要的计划和流程, 呵呵, 这些是个人的意见, 因为看代码实现过程中经历了N多了放弃和重看, 上面的流程也是针对个人而言的:), 图2是ACE中Reactor的主要组成成员, 这个是实现相关的, 重要的就是Reactor作为用户界面, 向具体的实现转发
云南火腿怎么做好吃 图2. ACE的Reactor的主要成员(实现)
下面就简要的把reactor的用户界面api初步的分个类[Reactor.h]:
ACE_Reactor 使用 pimp的方式, 我觉得应该是为了屏蔽底层的实现方式, 给用户提供一个统一的用户API界面, 里面只涉及到极少的逻辑, 其余都是API的转发调用. 但是这个类就展示了, 什么是一个Reactor[不一定好, 这个类, 太复杂感觉上]
1. ACE对reactor提供了单件和普通实例两种方式
砥砺奋进2. ACE初始化, 配置函数
3. 句
柄管理功能
4. 事件Loop功能
5. Timer管理功能
6. Single管理功能
7. 通知机制
8. 其他帮助函数
这里可以注意到, Reactor不仅仅有IO事件, 还可以有Timer和Single事件~~~这个一下子就变的复杂了, 但是现在的注意力集中在2, 3, 4这三点上. 下面就对它们做逐个的分析.
/html/JAVA/Struts/ /html/softeng/ /ComputerNetwork/os/Windwos2008/ WwW.FenGFLY.Com 软件工程ww
/html/shujuku/MySQL/ /html/JAVA/Struts/
电影海报图片原文来自:雨枫技术教程网
原文网址:/plus/view-173325-1.html
昨天记录了Reactor.h中的API的主要分类, 按功能分为
1. ACE对reactor提供了单件和普通实例两种方式
2. ACE初始化, 配置函数
3. 句柄管理功能
4. 事件Loop功能
5. Timer管理功能
6. Single管理功能
7. 通知机制
8. 其他帮助函数
下面详细的归类一下
1. ACE对reactor提供了单件和普通实例两种方式
Reactor类中的 ACE_Reactor *reactor_ 就是用来维护单件的, 但是提供了static的event_loop*一族函数, 并放在inl中, 现在还不清楚这些API有没有必要, 为什么不统一走非static的同名方法呢, 在实现上是没有什么区别, 只是为了调用的方便么, 个人认为如果是这样的原因, 就有点过了, 因为Reactor是一个用户API界面, 应该保持简单易用? 知道深层原因的大侠请拍砖账号英文
2. ACE初始化
在ACE_Reactor的构造函数ACE_Reactor (ACE_Reactor_Impl *impl =0,booldelete_implementation=fal)中可以看出来, 在构造是, 用户可以指明该Reactor的底层实现方式, 如果用户不指定, 那么在构造函数中, 在win32平台下, 会自动指定ACE_Msg_WFMO_Reactor或者ACE_WFMO_Reactor作为默认的底层实现, 在其他平台中, 会指定ACE_TP_Reactor, ACE_Dev_Poll_Reactor, ACE_Select_Reactor作为默认的底层实现.
底层实现由Reactor的成员变量ACE_Reactor_Impl *implementation_持有, 这个抽象类是pimp手法, 隔
离了用户API界面和底层实现.
值得注意的是 open( size_t max_number_of_handles, int restart = 0, ACE_Sig_Handler *signal_handler = 0, ACE_Timer_Queue *timer_queue = 0)这个函数, 是很有用了, 可以不调用, 因为在ACE_Reactor的构造函数中会用默认的参数先调用一次, 如果需要定制这些参数, 可以自己手动调用进行设置, 其中第二项是个有趣的参数, 如果不指定restart(即为0), 如果在lect阻塞的过程中被信号中断, 那么事件Loop就会退出, 如果指定restart>0那么这种情况下就会重启lect调用.
3. 句柄管理功能
包括register, remove, suspend, resume句柄, 这里不但有IO事件句柄, 还
可以有Single事件句柄, WIN32平台下有Event事件句柄
凉拌海蜇丝
4. 事件Loop功能
包括事件主循环, 检测主循环结束, 停止主循环功能, handle_events, work_pending, 后两者的目地可能是为了给用户自己实现Loop提供的接口
5. Timer管理功能
Timer的功能来自于ACE_Reator的基类ACE_Reactor_Timer_Interface, 包含对时间事件的支持包括插入一个Timer, 返回唯一的TimerID, 重置一个Timer, 取消一个Timer等操作
6. Single管理功能
管理信号事件, linux下的信号, 和win下的event
7. 通知机制
notify函数很重要, 给外部提供了一种控制reactor的方法, 可以是唤醒正在阻塞的lect, 也可以是投递一个用户自己指定的事件(把事件处理event_handle传进去), lect_reactor中的实现是通过一个pipe
8. 其他帮助函数
find_handler, initialized(测试reactor是否成功init), owner(设置reactor的所有者线程), implementation(设置reactor的底层实现)等等
~~~ACE里面的东西太精巧了, 想一下子看明白, 真的是越看越多, 不免就转到细节里了, 这里先大概分个类, 对其中的每一条再细细的分析, 这样才能比较彻底的了解Reactor的实现原理.
附:
萨芬
ACE_Reactor的内存结构, 很简单的内存结构, sizeof可能是9 = 4 + 4 + 1(未对齐, 没测过, YY, 反正是为了表达它很小的意思)
1. 一个vtab指针, 因为是继承了接口ACE_Reactor_Timer_Interface, 所以Reactor充当了事件事件的驱动者和管理者
2. ACE_Reactor_Impl *implementation_ 指向底层reactor的实现
3. bool delete_implementation_ ACE_Reactor在被析构时, 要不要把implementation_指向的也给析构掉, 注意, 默认参数是fal, 但在用户不给定implementation_情况下这个值是true, 因为这时implementation_是ACE自己new出来的, 他就自己delete, 符合"谁new谁delete", 如果这个implementation_是一个非new出来的, 当然这个值就只能是fal, 否者delete反而不对; 如果implementation_是用户自己new出来的, 那么最好在构造时指定这个参数为true, 否防止内存泄露.
原文来自:雨枫技术教程网
原文网址:/plus/view-173326-1.html
. ACE_Reactor构造函数, 定制Reator的底层实现机制
1. ACE_Reactor (ACE_Reactor_Impl *implementation = 0, bool delete_implementation = fal)
2. 在构造reactor时, 用户可以自己指定底层reactor的具体实现方式(实现方式见ACE_Reactor学习1图2), 通过第一个参数将实现和reactor绑定, 第二个参数是Reactor析构是是否调用delete将implementation 删掉, 前面一节也已有记录
3. 默认参数情况下, 底层实现将指定为ACE_WFMO_Reactor, ACE_Select_Reactor, ACE_Dev_Poll_Reactor
2. ACE_Reactor::open函数,
1. int open (size_t max_number_of_handles, int restart = 0,ACE_Sig_Handler *signal_handler = 0,ACE_Timer_Queue *timer_queue = 0)
2. 参数的含义比较明确, max_..支持最大的handler数, restart是党lect函数被中断后, 是停止Loop返回, 还是重启lect, signal_handler是对信号的处理的支持, timer_queue是对时间的处理的支持
3. open实际上是通过转发到底层的imp的open方法.以lect的实现为例子, 实际上这个函数的实现是在ACE_Select_Reactor_T::open中实现, 根据默认参数, 可以得出max_number_of_handles是当前系统中FD_SETSIZE的定义(比如windows下就是定义为1024), restart=0不重新启动lect(当lect被中断时), sig_hanle和timer_queue默认参数都是null
open的流程:
1. 检测是否inited, 及是否已经初始化, 防止多次初始化
2. 将reator的owner线程设置为自己, 这个很重要~~~这里就有一种假设, 就是如果你在同一个线程中创建lect_reactor, 并在这个线程里面去调用event_loop的话, 就不用显示调用owner将reactor和这个线程绑定, 因为这里的open函数表明:"reactor默认的owner是创建它的线程", 如果是在不同的线程中进行reactor的创建和event_loop, 那么在loop前必须用owner方法将线程和reactor绑定, 同一时刻reactor只能属于同一线程[注意, 在TP_Select中是另外一种机制]
3. 设置restart属性
4. 如果有可用的sig_handle(对应参数不为null), 那么设置reactor的sig_handler, 否者new一个ace_sig_handler
5. 如果有可用的timer_handle(同上), 那么设置reactor的timer_handler, 否者new一个ace_timer_heap(时间按堆组成)
6. 如果有可用的notify_handle(同上), 那么设置reactor的notify_handler, 否者new一个ace_lect_reactor_notify, 并打开
7. 如果上述操作成功, 设置inited=true
注意: 注意这个imp->open的调用时机, 根据代码中来看, 在lect_reactor的两个构造函数中, 都会调用open函数, 也就是说这个open函数是不用手动去调用的, 你手动调用时, open函数会在步骤1中return掉, 但是reactor中还是给出了open这样一个接口, 其实现是调用imp->open, 呵呵, 为什么要这个接口, 它存在的意义是什么? 也许是为了别的实现来说有用, 但是不管怎么这个接口的存在都让人理解reactor增加了难度~~~
3. 总结:
1. reacotr的初始化总结[以lect为例]
1. 用户自己定义一个reactor_imp, 在reactor_imp的构造函数中会调用open, 把一切都初始化好[初始化Core]
2. 将reactor_imp和一个reactor绑定起来, 然后使用reactor的一致的接口来操作reactor_imp[绑定Interface]
仔细理解这两句话, 真的觉得这种手法十分的强大, 通过一个安装过程, 将一个Core(
功能内核)和一个Interface(接口界面)绑定在一起. 即提供了一个一致的访问界面, 也提供了一个可以拔插替换的核心~~~~不由的对ace的作者充满敬意, 虽然看过设计模式, 虽然了解一些解耦合的方法, 哪有怎样?? 能真正把这些思想和方法在实际的工作实践中运用到自如的人, 真的是太厉害了:)
ps: 注意细节, 用静态ACEs.lib时, 不但要把lib包进来, 而且在工程中要定义ACE_AS_STATIC_LIBS, 否则会发生link error
我想日
WWW.FENGFLY.COM
/html/ERP/OA/OAshishi//html/ERP/xinxianquan/ 雨 枫技 术 教程 网
原文来自:雨枫技术教程网
原文网址:/plus/view-173327-1.html
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* ba_ 真正的原始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是一个比