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的更多相关文章

  1. ZeroC ICE的远程调用框架 Slice如何帮助我们进行Ice异步编程(AMI,AMD)

    Slice最大的用处就是为我们使用Ice进行编程,代劳绝大部分的重复性代码,并提供一些帮助性的框架代码,如用于AMI和AMD方式进行异步编程的回调框架. 当Slice不为我们生成代码时,我们仍然可以按 ...

  2. ZeroC ICE的远程调用框架 AMD

    继上一篇<ZeroC ICE的远程调用框架>,本篇再来说其中的AMD.(本篇需要重写) 当在ice文件中声明某个接口方法Method为["amd"]后,接口方法在stu ...

  3. ZeroC ICE的远程调用框架

    想搞清楚slice为我们生成了什么样的框架代码,就先搞明白Ice的远程调用框架暗中为我们做了些什么? Ice将Ice Object的方法调用分为三个阶段(或步骤),分别是begin,process和e ...

  4. ZeroC ICE的远程调用框架 AMI与AMD -Why?

    在Ice有两种异步使用的方式,AMI和AMD.AMI是异步方法调用,AMD是异步方法调度(分派).前者用在代理端,后者用在饲服实现端. AMI其实就是在代理端,使用Future机制进行异步调用,而不阻 ...

  5. ZeroC ICE的远程调用框架 Callback(一)-AMI异步方法调用框架

    Ice框架提供了不少回调设施,其中一些是使用Ice远程调用进行ami模式或amd模式的支撑.本篇来看一下用于代理端的回调设施. Ice代码中有好几个Callback相关命名的基类,并且slice还会为 ...

  6. ZeroC ICE的远程调用框架 class与interface

    我们在ice文件中定义的class或interface,slice都会为我们生成stub存根类和skeleton骨架类.在这里要注意slice并没有分别生成两份单独用在客户端或服务端的接口给开发分发. ...

  7. ZeroC ICE的远程调用框架 ServantLocator与Locator

    ServantLocator定位的目标是Servant,而Locator定位的目标是“Ice Object”,即一个可定位的“Ice Object”代理.Servant是::Ice::Object的继 ...

  8. ZeroC ICE的远程调用框架 代理引用地址

    在官方文档中称为Binding,协议-地址对的绑定.在Proxy模式中,一般地有三个参与者,Proxy,Subject以及RealSubject.Subject定义了Proxy(代理)和RealSub ...

  9. ZeroC ICE的远程调用框架 ASM与defaultServant,ServantLocator

    ASM与defaultServant,ServantLocator都是与调用调度(Dispatch)相关的. ASM是ServantManager中的一张二维表_servantMapMap,默认Ser ...

随机推荐

  1. linux自启动脚本.sh

    while [ 1 ]; do              PRO_NUM=`ps -ef | grep "cms$" | grep -v "grep" | wc ...

  2. Java中线程与堆栈的关系

    栈是线程私有的,每个线程都是自己的栈,每个线程中的每个方法在执行的同时会创建一个栈帧用于存局部变量表.操作数栈.动态链接.方法返回地址等信息.每一个方法从调用到执行完毕的过程,就对应着一个栈帧在虚拟机 ...

  3. mysql 主从关系ERROR 1872 (HY000): Slave failed to initialize relay log info structure from the repository

    连接 amoeba-mysql出现Could not create a validated object, cause: ValidateObject failed mysql> start s ...

  4. ssh终端远程登陆主机命令--笔记

    ssh终端远程登陆主机命令 ssh user@host ssh optadmin@10.55.45.38

  5. Python 的多线程是鸡肋?

    "唉,还没毕业就受到甲方的支配,等以后进了公司可咋整啊."小白嘴里这么吐槽,但心理上还是不敢怠慢,只能恋恋不舍地关掉眼前的游戏,打开了 Python 代码思考了起来. " ...

  6. javascript单线程,异步与执行机制

    js的单线程模型与游览器的进程/线程息息相关,在了解js单线程与异步的时候,建议先看看这篇文章 为什么是单线程 由于js是可操作dom的,如果js是多线程,在多线程的交互下,处于界面中的dom节点就可 ...

  7. Java多线程编程(二)对象及变量的并发访问

    一.synchronized同步方法 1.方法内的变量为线程安全 “非线程安全”问题存在于“实例变量”中,如果是方法内部的私有变量,则不存在“非线程安全”问题,所得结果也就是“线程安全”的了. 示例: ...

  8. 设计模式(二十一)Proxy模式

    在面向对象编程中,“本人”和“代理人”都是对象.如果“本人”对象太忙了,有些工作无法自己亲自完成,就将其交给“代理人”对象负责. 示例程序的类图. 示例程序的时序图.从这个时序图可以看出,直到调用pr ...

  9. unity发布ios高通AR的问题

    1)缺少引用,无法找到vuforiaBehavior 原因:Windows下的工程,直接考到mac下,导致unity自带插件(2017)有问题 解决:首先在playerSettings-xrSetti ...

  10. python中基本运算符

    基本运算符 a // b 取整 a % b 取余 a ** b a 的b次方 a == b 判断运算符左右两边值是否相等 a != b 判断运算符左右两边值是否不等 a > b a >= ...