ZeroC ICE的远程调用框架 ThreadPool
ThreadPool提供Reactor/Proactor服务,并且强偶合了Reactor(反应器)/Proactor(前摄器)。不同于Reactor/Proactor使用线程池
进行事件处理的设计。如ACE框架的ACE_TP_Reactor。
同时ThreadPool提供一个共享的工作分派队列,可以用作Half-Async/Half-sync并发模式的线程池。
ThreadPool为池中每个线程定制了一至的线程循环,运行在池中的线程者必须进行这个循环,接受线程池的统一控制。
此外ThreadPool还强偶合了每一个事件处理类,线池程的相关控制也偶合进事件处理程序中去。
ThreadPool组件包含下面的协作类:
ThreadPoolCurrent,是ThreadPool和EventHandlerThread的一个关联
EventHandlerThread,运行在ThreadPool的线程。
Selector,反应器(当不使用IOCP),或前摄器(当使用IOCP)。
ThreadPoolWorkQueue,工作分派队列,优先级别比网络IO事件低。使用ThreadPool进行dispatch的任务都入队到ThreadPoolWorkQueue
。
EventHandler,定义了可以在线程池执行的事件处理程序的抽象接口。
ThreadPool组件只处理(或者说提供现成的)三种具体的事件:
ThreadPoolWorkQueue,工作队列消费事件。
ConnectionI,网络连接上读写事件,它的事件处理程序强偶合了Ice协议。
IncomingConnectionFactory,被动网络连接事件。
这里要指出ThreadPool还强偶合了上面每一个事件处理类,线池程的相关控制也偶合进事件处理程序"EventHandler::message"中去。
下面还会进一步说明。
相信这时你一定很想听到ThreadPool使用了高性能的Leader/Followers并发模式了。但是要清楚不是使用了LF模式就代表你的软件就高
性能了,LF模式虽然说高性能但也不是什么情况都使用,LF模式是设计用来解决某些模式在某些特定情况的问题的。在Ice的
ThreadPool组件设计中,在使用IOCP前摄器的版本就没有使用LF模式。为什么?因为LF模式不是最佳的选择,在使用IOCP的前摄器没有
LF模式针对解决的问题发生,反而帮倒忙。
ThreadPool组件在使用Reactor(反应器)的版本使用Leader/Followers并发模式,而在Proactor(前摄器)的版本不使用
Leader/Followers并发模式。
ThreadPool组件使用单方法分派接口策略,同一句柄的所有事件类型的事件处理集中在一个单独的事件处理方法。而ACE的设计则是使
用多方法分派接口策略,同一句柄不同事件类型的事件处理分别对应特定的事件处理钩子方法。ThreadPool组件使用单方法分派接口策
略,将具体的事件类型分派交给事件处理方法内进行,而不是由Reactor(反应器)或Proactor(前摄器)最终决定。
EventHandler是一个抽象类,虽然定义了事件处理抽象方法message,却同时也定义事件状态。
事件类型包含Read,Write等,由SocketOperation枚举类型来定义。
EventHandler定义许多由SocketOperation组成的状态。
用于控制的状态:_registered,_ready,_disable。
_registered:一个具体的事件处理类关联到ThreadPool(反应器或前摄器强偶合在ThreadPool)。
_ready:从反应器或前摄器接收事件的逻辑之外,对事件进行激活。
_disable:使用反应器版本的ThreadPool的动态控制。
用于前摄器异步操作状态:_pending,_started,_completed。
_pending:
_started:发起了一次异步I/O操作
_completed:发起了的一次异步I/O操作完成了
此外,EventHandler不保存由反应器或前摄器接收到事件的接收状态,而是在ThreadPool的map容器中,由线程池线程共享。
ThreadPool将事件处理程序分为两阶段,第一阶段是IO,第二阶段是User。在使用Reactor(反应器)版本中,网络指示事件通知了句
柄不再阻塞,可以放心进行同步I/O操作,所以事件处理程序首先要对指示事件进行响应进行同步I/O操作,然后才是事件用于I/O以外
的操作,也就是真正的dispatch。在使用Proactor(前摄器)版本中,事件处理程序并不包含第一阶段,因为异步I/O操作由系统进行
了,并且事件是异步I/O操作的完成事件。ThreadPool统计这两个阶段的事件处理状态的线程数量,用来对线程池整体的控制。
ThreadPool使用_inUseIO对事件处理进行IO阶段的线程统计,_inUse对事件处理进行dipatch阶段的线程统计。
_inUseIO统计数决定是否要进行Leader的推选(promote),只有在反应器版本有效。每次线程以leader身份取出一个事件处理对象,
对相关事件进行同步I/O之前,都要参加统计计数即加1。在完成同步I/O之后,释放统计计数即减1,并根据统计是否要推选。因为反应
器不希望有句柄进行同步I/O的同时而进行阻塞等待句柄的事件。当还有已得事件未处理时,则不用理会这个统计计数而进行推选唤醒
线程处理已得事件。
_inUse统计数决定是否要新增线程,如果正在dispatch的线程数量已经到达了当前ThreadPool拥有的线程数目,还未到达最大限制数目
的时候,必须新增线程。
因为ThreadPool组件在使用LF模式的版本中,引入了_inUseIO统计数来控制竞选的进程(progress,是否允许新一轮的竞选)。并且这
个_inUseIO统计数的功能强偶合进了事件处理类(EventHandler的继承类)的事件处理程序(EventHandler::message)中,事件处理
程序必须对_inUseIO统计数进行释放,如果这个_inUseIO统计数发生了意外,你的LF竞选可能就永远不会进行新一轮的选举,以至候选
线程不可能被唤醒。如果你不明白这一点,去添加自己的事件处理类的话,就可能因没有在事件处理程序中释放这个_inUseIO统计数而
惹上麻烦。虽然Ice在ThreadPool的线程循环里,在事件处理程序执行之后小心地照料了这个_inUseIO统计数,但还是有可能事件处理
程序异常等其它原因,使得你没的程序运行没有按照Ice设计的流程进行,只要有一次_inUseIO统计数没有被正确释放,你的线程池就
会惹上麻烦。
此外,ThreadPool引入的另一个用于线程池控制的统计数_inUse,同样也强偶合在事件处理程序。并且由这个_inUse统计数感知压力而
新增线程的工作也是偶合在事件处理程序。当这个统计数发生错乱后,你可以失去以下便利。尽管你的线程池线程数目没有达到上限,
当前可用线程都用尽了,但也不能新添加线程。而你池中有线程因为异常面退出了,线程池规模缩小,却不能新添加线程补充。
由于ThreadPool引入了上面一些统计数来控制线程池,因此线程池的线程对象EventHandlerThread有下面几种状态:Idle,ForIO,
ForUser等。当线程在上面的状态切换时,都要通知相关的observer。ThreadPool的线程执行的整个流程中,还有许多的事件监视点,
即有许多各类的Observer,这将分开一篇独立写。
ThreadPool提供默认dispatch策略,以及支持自定义dispatcher策略。默认dispatch策略,事件处理执行在当前线程。自定义
dispatcher策略则由用户自定义,并在Ice环境Communicator创建时指定。
ZeroC ICE的远程调用框架 ThreadPool的更多相关文章
- ZeroC ICE的远程调用框架 Slice如何帮助我们进行Ice异步编程(AMI,AMD)
Slice最大的用处就是为我们使用Ice进行编程,代劳绝大部分的重复性代码,并提供一些帮助性的框架代码,如用于AMI和AMD方式进行异步编程的回调框架. 当Slice不为我们生成代码时,我们仍然可以按 ...
- ZeroC ICE的远程调用框架 AMD
继上一篇<ZeroC ICE的远程调用框架>,本篇再来说其中的AMD.(本篇需要重写) 当在ice文件中声明某个接口方法Method为["amd"]后,接口方法在stu ...
- ZeroC ICE的远程调用框架
想搞清楚slice为我们生成了什么样的框架代码,就先搞明白Ice的远程调用框架暗中为我们做了些什么? Ice将Ice Object的方法调用分为三个阶段(或步骤),分别是begin,process和e ...
- ZeroC ICE的远程调用框架 AMI与AMD -Why?
在Ice有两种异步使用的方式,AMI和AMD.AMI是异步方法调用,AMD是异步方法调度(分派).前者用在代理端,后者用在饲服实现端. AMI其实就是在代理端,使用Future机制进行异步调用,而不阻 ...
- ZeroC ICE的远程调用框架 Callback(一)-AMI异步方法调用框架
Ice框架提供了不少回调设施,其中一些是使用Ice远程调用进行ami模式或amd模式的支撑.本篇来看一下用于代理端的回调设施. Ice代码中有好几个Callback相关命名的基类,并且slice还会为 ...
- ZeroC ICE的远程调用框架 class与interface
我们在ice文件中定义的class或interface,slice都会为我们生成stub存根类和skeleton骨架类.在这里要注意slice并没有分别生成两份单独用在客户端或服务端的接口给开发分发. ...
- ZeroC ICE的远程调用框架 ServantLocator与Locator
ServantLocator定位的目标是Servant,而Locator定位的目标是“Ice Object”,即一个可定位的“Ice Object”代理.Servant是::Ice::Object的继 ...
- ZeroC ICE的远程调用框架 代理引用地址
在官方文档中称为Binding,协议-地址对的绑定.在Proxy模式中,一般地有三个参与者,Proxy,Subject以及RealSubject.Subject定义了Proxy(代理)和RealSub ...
- ZeroC ICE的远程调用框架 ASM与defaultServant,ServantLocator
ASM与defaultServant,ServantLocator都是与调用调度(Dispatch)相关的. ASM是ServantManager中的一张二维表_servantMapMap,默认Ser ...
随机推荐
- std::lock_guard 与 std::unique_lock
std::lock_guard 与 std::unique_lock 对 mutex 进行自动加解锁. mutex m; void fun() { unique_lock<mutex> m ...
- Spring Boot 2.X(十一):全局异常处理
前言 在 Java Web 系统开发中,不管是 Controller 层.Service 层还是 Dao 层,都有可能抛出异常.如果在每个方法中加上各种 try catch 的异常处理代码,那样会使代 ...
- JavaScript Array返回值以及是否改变原数组。
1. push:最后一位新增://改变原数组 arr.push("123"); 返回值是数组的长度: var b = ...
- 如何使用代理IP进行数据抓取,PHP爬虫抓取亚马逊商品数据
什么是代理?什么情况下会用到代理IP? 代理服务器(Proxy Server),其功能就是代用户去取得网络信息,然后返回给用户.形象的说:它是网络信息的中转站.通过代理IP访问目标站,可以隐藏用户的真 ...
- 惊人!Spring5 AOP 默认使用Cglib ?从现象到源码深度分析
Spring5 AOP 默认使用 Cglib 了?我第一次听到这个说法是在一个微信群里: 真的假的?查阅文档 刚看到这个说法的时候,我是保持怀疑态度的. 大家都知道 Spring5 之前的版本 AOP ...
- solr学习篇(二) solr 分词器篇
关于solr7.4搭建与配置可以参考 solr7.4 安装配置篇 在这里我们探讨一下分词的配置 目录 关于分词 配置分词 验证成功 1.关于分词 1.分词是指将一个中文词语拆成若干个词,提供搜索引擎 ...
- OptimalSolution(1)--递归和动态规划(3)数组和字符串问题
一.最长递增子序列(LIS) 给定数组arr,返回arr的最长递增子序列.例如,arr={2,1,5,3,6,4,8,9,7},返回的最长递增子序列为{1,3,4,5,8,9} 1.时间复杂度为O(N ...
- 源码学习系列之SpringBoot自动配置(篇一)
源码学习系列之SpringBoot自动配置源码学习(篇一) ok,本博客尝试跟一下Springboot的自动配置源码,做一下笔记记录,自动配置是Springboot的一个很关键的特性,也容易被忽略的属 ...
- 利用span设置文字固定宽度
<input type="radio" name="dispMode" id="rdoManul" value="manul ...
- UIScrollView的contentView 助于理解