以上三节尚且漏掉一点,就是作业控制。如果没有设置作业控制,那么TNonBlockingServer默认接收到作业就立即执行,整个变成了一个串行的结构,完全失去了使用TNonBlockingServer的意义。一般的作业控制,使用SimpleThreadManager即可。他继承基本的ThreadManager,并提供了一个启动ThreadManager的简易流程:设置最长作业队列——开启作业控制——添加Worker。
Worker是ThreadManager的调度封装,每个Worker都有一个run方法,他是实际的作业执行者。由于这个函数要和addWorker、removeWorker等函数进行同步,因此里面有三个Monitor对象,调用wait和signal方法。忽略掉这些逻辑,剩下的就是清除过期的作业、调用removeNextPending从作业队列不停的取出作业,调用作业的run方法。
之前提到,实际的请求处理,也就是作业是TConnection::Task::run。在作业调度一层,用Task结构对TConnection::Task又进行了一层封装调用。而Worker处理的作业单元就是一个Task,经过层层run方法的调用(这个程序员前身一定是写Java的,爱用Runnable接口爱的不行!),最终将调用请求处理的process方法。
回过头来说那几个monitor。这里有个概念,workerMaxCount_并不是支持的最大执行者槽,而是设置的最大执行者槽。每次AddWorker或者RemoveWorker,这个值都会改变。而实际运行的执行者,并不一定是最大执行者的数目,因为一些执行者的状态可以为非active,放入deadWorkers_。AddWorker和RemoveWorker都是阻塞的行为,即只有执行者确实添加并且运行/死亡,函数才会返回。而同步就靠workerMonitor。
等待执行的作业(pending task)是有明确的数目限制的,上节提到,TConnection做AddTask的时候,一旦超出最大值就会根据策略采取不同的手段。如果不操作,就会在add函数中阻塞。当有作业执行结束的时候,便可以唤醒一个阻塞的add操作,将作业加入队列。这种操作由maxMonitor同步。
最后还有一个叫monitor的monitor(这不是人话!)。他是协调当作业执行的快、加入的慢的情况。当一个执行者执行完一次作业,他会重新从作业队列中获取一个,如果获取不到,就阻塞。因此,当一个新的作业进入作业队列时,会进行一次执行者唤醒。这个过程就是monitor所指明的。
当然,ThreadManager也包括了加入作业等等的基本操作,要不然哪里来的作业呢。