ACE_Reactor(六)ACE_TP_Reactor

源码可以到http://www.aoc.nrao.edu/php/tjuerges/ALMA/ACE-5.5.2/html/ace/上去找

虽然ACE_Select_Reactor是灵活的,但是由于只有拥有者才能调用它的handle_events方法,所以在多线程应用程序中它还是有一定的局限性的,因而ACE_Select_Reactor得事件多路分离层的序列化处理可能对某些场景来讲约束太多了。一种解决方法是多个线程去运行独立ACE_Select_Reactor的实例,但是这样需要开发人员去实现一个代理在各反应器之间均衡的分配事件处理,以便达到均衡负载。另一种即这里的ACE_TP_Reactor,基于线程池的Reactor。
其实现了Learder/Follower模型,从而提供了一种有效的并发性模型,多个线程可以针对一组I/O句柄轮流调用select去检测并处理事件。

最关键的地方在于:
1.分派事件(其实就是该线程自己执行事件处理函数)前,会释放Token,让其他线程能够去select或者处理还未处理的事件
2.获取到token的线程,会先检测是否有未处理的事件,若有则先处理,若没有则占用token进行select阻塞检测事件

这里的keypoint1,可以从如下代码中看出来:


int ACE_TP_Reactor::handle_socket_events    (   int &   event_count,
ACE_TP_Token_Guard &    g
)
00466 {
00467 
00468   // We got the lock, lets handle some I/O events.
00469   ACE_EH_Dispatch_Info dispatch_info;
00470 
00471   this->get_socket_event_info (dispatch_info);
00472 
00473   // If there is any event handler that is ready to be dispatched, the
00474   // dispatch information is recorded in dispatch_info.
00475   if (!dispatch_info.dispatch ())
00476     {
00477       return 0;
00478     }
00479 
00480   // Suspend the handler so that other threads don't start dispatching
00481   // it, if we can't suspend then return directly
00482   //
00483   // NOTE: This check was performed in older versions of the
00484   // TP_Reactor. Looks like it is a waste..
00485   if (dispatch_info.event_handler_ != this->notify_handler_)
00486     if (this->suspend_i (dispatch_info.handle_) == -1)
00487       return 0;
00488 
00489   // Call add_reference() if needed.
00490   if (dispatch_info.reference_counting_required_)
00491     dispatch_info.event_handler_->add_reference ();
00492 
00493   // Release the lock.  Others threads can start waiting.
00494   guard.release_token ();
00495 
00496   int result = 0;
00497 
00498   // If there was an event handler ready, dispatch it.
00499   // Decrement the event left
00500   --event_count;
00501 
00502   // Dispatched an event
00503   if (this->dispatch_socket_event (dispatch_info) == 0)
00504     ++result;
00505 
00506   return result;
00507 }

上述的第一点,也即是这里的:

00493   // Release the lock.  Others threads can start waiting.
00494   guard.release_token ();

说明里也讲的很清楚,会将token释放让其他线程去等待。

那么keypoint2,又是如何完成的了呢?看下面的代码:

int ACE_TP_Reactor::get_event_for_dispatching   (   ACE_Time_Value *    max_wait_time    ) 
00511 {
00512   // If the reactor handler state has changed, clear any remembered
00513   // ready bits and re-scan from the master wait_set.
        .............
00534   return this->wait_for_multiple_events (this->ready_set_,
00535                                          max_wait_time);
00536 }
//看下wait_for_multiple_events的实现

template<class ACE_SELECT_REACTOR_TOKEN>
int ACE_Select_Reactor_T< ACE_SELECT_REACTOR_TOKEN >::wait_for_multiple_events  (   ACE_Select_Reactor_Handle_Set &     ,
ACE_Time_Value *    
) 
01074 {
01075   ACE_TRACE ("ACE_Select_Reactor_T::wait_for_multiple_events");
01076   u_long width = 0;
01077   ACE_Time_Value timer_buf (0);
01078   ACE_Time_Value *this_timeout;
01079 
01080   int number_of_active_handles = this->any_ready (dispatch_set);
01081 
01082   // If there are any bits enabled in the  then we'll
01083   // handle those first, otherwise we'll block in