zoukankan      html  css  js  c++  java
  • 调试C++NPv2_Select_Reactor_Log_Server程序

           调试C++NPv2_Select_Reactor_Log_Server程序,main函数中声明变量ACE_Select_Reactor select_reactor;。在aceSelect_Reactor.h文件中typedef ACE_Select_Reactor_T<ACE_Select_Reactor_Token> ACE_Select_Reactor;声明类型。调试进入到模板类ACE_Select_Reactor_T的构造函数中,调用模板类方法open,该函数会调用到ACE_Select_Reactor_Notify::open函数进而调用ACE_Pipe::open函数。这个函数最终会调用::getaddrinfo函数,然后用procexp.exe工具查看当执行这条语句::getaddrinfo后程序会多一个线程ntdll.dll!_allmul,这个线程状态为等待。msdn以getaddrinfo作为关键字来搜索,然后vs运行里程,调试运行发现当执行getaddrinfo语句后并没有新增一个线程,后来将getaddrinfo的第三个参数struct addrinfo hints;赋值为C++NPv2_Select_Reactor_Log_Server程序中的值,再次调试运行程序当执行完这条语句用procexp.exe工具查看就会新增一个线程。具体就是将struct addrinfo的ai_flags成员修改为AI_V4MAPPED,将AI_V4MAPPED成员修改为AF_INET。在C++NPv2_Select_Reactor_Log_Server例子的main函数中分别以event_loop和controller作为线程函数创建了两个线程,由前面分析再加上主线程,所以运行完该例子后用工具procexp.exe查看总共是4个线程。当在另外一个电脑来调试该程序时,用procexp.exe来查看则多了两个线程,Start Address都为sdckern.dll!Ordinal362+0xXXX;用VS2013调试一个简单的cpp工程,仅仅是进入到main函数中,用procexp.exe查看也是有这样两个线程。

           调试C++NPv2_Select_Reactor_Log_Server例子,main函数中定义ACE_Select_Reactor select_reactor;变量,在该例子中ACE_Select_Reactor被定义为ACE_Select_Reactor_T<ACE_Reactor_Token_T<ACE_Token>>。定义该变量会调用模板类的构造函数,构造函数中调用模板类的open函数即ACE_Select_Reactor_T<ACE_Reactor_Token_T<ACE_Token> >::open,进而通过定义在模板类ACE_Select_Reactor_T的父类ACE_Select_Reactor_Impl中的成员变量ACE_Reactor_Notify *notify_handler_;,来调用ACE_Select_Reactor_Notify::open函数,在该函数中分别调用其成员ACE_Pipe notification_pipe_;、ACE_Notification_Queue notification_queue_;的open函数,在该函数的开始将ACE_Select_Reactor_T模板对象赋值给其成员ACE_Select_Reactor_Impl *select_reactor_;,然后通过该成员调用模板类的register_handler函数,在这里即ACE_Select_Reactor_T<ACE_Reactor_Token_T<ACE_Token> >::register_handler函数,将ACE_Select_Reactor_Notify类的成员ACE_Pipe notification_pipe_;的读端句柄注册给模板类的成员ACE_Select_Reactor_Handler_Repository handler_rep_;,该成员定义在父类ACE_Select_Reactor_Impl中。

           函数ACE_Select_Reactor_T<ACE_Reactor_Token_T<ACE_Token> >::register_handler会调用this->register_handler_函数,进而调用ACE_Select_Reactor_Handler_Repository::bind函数,同样注册到ACE_Select_Reactor_Handler_Repository的还有监听套接口,在examplesC++NPv2Logging_Acceptor.cpp文件的Logging_Acceptor::open函数中调用ACE_Reactor::register_handler函数,进而调用ACE_Select_Reactor_T<ACE_Reactor_Token_T<ACE_Token> >::register_handler函数,最终调用ACE_Select_Reactor_Handler_Repository::bind函数。

           main函数中分别以线程函数event_loop和controller创建两个线程。运行线程函数event_loop会调用ACE_Reactor::run_reactor_event_loop函数,该函数的while循环中调用模板类ACE_Select_Reactor_T的handle_events函数,在这里即ACE_Select_Reactor_T<ACE_Reactor_Token_T<ACE_Token> >::handle_events。该函数中调用执行this->handle_events_i。

           模板类函数ACE_Select_Reactor_T<ACE_SELECT_REACTOR_TOKEN>::handle_events_i调用执行this->wait_for_multiple_events函数,该函数中调用ACE_OS::select函数,用select模型来监测触发事件。aceOS_NS_sys_select.inl文件中定义的ACE_OS::select函数的参数包含fd_set *类型,这里调用以ACE_Handle_Set类型作为实参,所以需要ACE_Handle_Set类的类型转换。aceOS_NS_sys_select.inl文件中定义的ACE_OS::select函数中用到了const timeval *指针,该指针当ACE_OS::select函数的最后一个参数onst ACE_Time_Value *非空时,将该参数转换为const timeval *指针。这里也用到了ACE_Time_Value类的类型转换,因为参数为指针,所以先解引用,然后默认执行类的类型转换函数。 

           根据以上分析,当main函数调用ACE_Reactor::run_reactor_event_loop函数,进而调用ACE_Select_Reactor_T<ACE_Reactor_Token_T<ACE_Token> >::handle_events函数,最终调用ACE_Select_Reactor_T<ACE_Reactor_Token_T<ACE_Token> >::wait_for_multiple_events函数,该函数中调用ACE_OS::select函数,在该函数中会阻塞在::select系统调用上,等待客户端的连接或者ACE_Select_Reactor_Notify类的成员变量ACE_Pipe notification_pipe_;的读端,而ACE_Reactor_Notify *notify_handler_;对象则包含在模板类ACE_Select_Reactor_T的基类ACE_Select_Reactor_Impl中,该成员在类ACE_Select_Reactor_Impl中用protected来修饰。当服务端启动后输入quit退出则会调用ACE_Reactor::notify函数,该函数又调用ACE_Select_Reactor_T<ACE_Reactor_Token_T<ACE_Token> >::notify函数,进而调用ACE_Select_Reactor_Notify::notify函数,在该函数中通过其成员ACE_Pipe notification_pipe_;的写端发送数据,这样前面的event_loop线程调用ACE_OS::select函数就会返回。 

           服务端启动后输入quit退出,线程函数event_loop最终调用ACE_OS::select函数会返回,ACE_Select_Reactor_T<ACE_Reactor_Token_T<ACE_Token> >::handle_events_i函数会继续调用执行this->dispatch,该函数中while循环去处理返回的触发事件集,在这个quit退出的流程中执行的是this->dispatch_notification_handlers,即ACE_Select_Reactor_T<ACE_Reactor_Token_T<ACE_Token> >::dispatch_notification_handlers函数,在该函数中调用ACE_Select_Reactor_Notify::dispatch_notifications函数,进而调用ACE_Select_Reactor_Notify::handle_input函数,由于触发事件的句柄为成员变量ACE_Pipe notification_pipe_;的读端句柄,所以当该函数先调用ACE_Select_Reactor_Notify::read_notify_pipe函数时,传递的参数即为管道的读端句柄,该函数接收写端句柄发送的消息存入在ACE_Notification_Buffer类型的变量中。这个变量即为前面调用ACE_Select_Reactor_Notify::notify函数中所封装的ACE_Notification_Buffer变量。 

           函数ACE_Select_Reactor_Notify::handle_input中读到ACE_Notification_Buffer变量后调用ACE_Select_Reactor_Notify::dispatch_notify函数,进而调用Quit_Handler::handle_exception函数,该函数中调用ACE_Reactor::end_reactor_event_loop函数结束事件循环。 

           服务端启动后输入quit退出,在ACE_Select_Reactor_Notify::notify函数中构造一个ACE_Notification_Buffer buffer变量后,调用ACE_Notification_Queue::push_new_notification函数将其放入通知队列,然后再调用ACE::send通过管道的写端发送到管道的读端。所以在ACE_Select_Reactor_Notify::handle_input函数中先调用ACE_Select_Reactor_Notify::read_notify_pipe函数读到ACE_Notification_Buffer buffer变量,然后再调用ACE_Select_Reactor_Notify::dispatch_notify函数,该函数中将之前的ACE_Notification_Buffer buffer变量作为引用参数的实参。而这个函数调用ACE_Notification_Queue::pop_next_notification函数读出一个ACE_Notification_Buffer变量来对参数赋值,其实这个地方调试发现这两个ACE_Notification_Buffer buffer变量是一样的。ACE_Select_Reactor_Notify::dispatch_notify函数的后面会根据ACE_Event_Handler类的枚举变量来分别处理,此处由于默认为EXCEPT_MASK,所以调用执行event_handler->handle_exception函数,此处即Quit_Handler::handle_exception。 

           模板类ACE_Select_Reactor_T的基类ACE_Select_Reactor_Impl中定义了成员变量ACE_Reactor_Notify *notify_handler_;,模板类的构造函数中调用其open成员方法,该方法中初始化该成员为继承自ACE_Reactor_Notify类的ACE_Select_Reactor_Notify类型,该类包含成员变量ACE_Notification_Queue notification_queue_;。

           类ACE_Notification_Queue包含成员变量Buffer_List notify_queue_;(//Keeps track of all pending notifications.)、Buffer_List free_queue_;(//Keeps track of all free buffers.)及ACE_Unbounded_Queue <ACE_Notification_Queue_Node*> alloc_queue_;,其中声明类型:typedef ACE_Intrusive_List<ACE_Notification_Queue_Node> Buffer_List;。关于alloc_queue_变量注释为“为了跟踪已分配的ACE_Notification_Buffer类型数组,通过一次分配多个ACE_Notification_Buffer对象来降低分配成本”。基类ACE_Select_Reactor_T的open方法中调用ACE_Select_Reactor_Notify::open函数,该函数中又调用ACE_Notification_Queue::open函数,该方法调用成员函数allocate_more_buffers函数,该函数中先创建ACE_REACTOR_NOTIFICATION_ARRAY_SIZE(默认为1024)个ACE_Notification_Queue_Node对象,然后通过其成员变量ACE_Unbounded_Queue <ACE_Notification_Queue_Node*> alloc_queue_;调用ACE_Unbounded_Queue<T>::enqueue_head函数。

           模板类ACE_Unbounded_Queue包含成员变量ACE_Node<T> *head_;(//Pointer to the dummy node in the circular linked Queue.)和size_t cur_size_;(// Current size of the queue.)。而模板类ACE_Node则包含成员变量ACE_Node<T, C> *next_;(//Pointer to next element in the list of ACE_Nodes.)。ACE_Unbounded_Queue的构造函数中初始化其成员变量ACE_Node<T> *head_;,注意对其注释为“在环形链队列中指向一个假节点”。现在回到前面ACE_Notification_Queue::allocate_more_buffers函数中调用的ACE_Unbounded_Queue<T>::enqueue_head函数,该函数中先将ACE_Notification_Queue::allocate_more_buffers中创建的指向1024个ACE_Notification_Queue_Node对象的指针作为参数创建ACE_Node<T>对象,此处即ACE_Node<ACE_Notification_Queue_Node*>,然后与ACE_Notification_Queue构造函数中创建的假节点ACE_Node<T>形成一个环形链。然后将模板类ACE_Unbounded_Queue的成员变量size_t cur_size_;自增。

           再回到ACE_Notification_Queue::allocate_more_buffers函数,初始化类成员变量ACE_Intrusive_List<ACE_Notification_Queue_Node> free_queue_;。模板类ACE_Intrusive_List包含成员变量 T *head_;(//Head of the list)和T *tail_;(//Tail of the list)。此处将创建的1024个ACE_Notification_Queue_Node对象用模板类ACE_Intrusive_List的成员变量 T *head_;和T *tail_;串起来。

           当调用ACE_Select_Reactor_Notify::notify函数,该函数会调用ACE_Notification_Queue::push_new_notification函数,该函数先取出空闲队列的头,即ACE_Notification_Queue_Node *对象,然后以ACE_Notification_Queue::push_new_notification函数的参数调用ACE_Notification_Queue_Node::set函数,然后通过调用ACE_Intrusive_List<T>::push_back函数,将该ACE_Notification_Queue_Node *对象串接在通知队列notify_queue_的结尾。

           当调用ACE_Select_Reactor_Notify::dispatch_notify函数时,先调用ACE_Notification_Queue::pop_next_notification函数取出ACE_Notification_Buffer对象,然后根据这个对象进行相应的处理。ACE_Notification_Queue::pop_next_notification函数通过调用ACE_Intrusive_List<T>::pop_front函数,取出通知队列notify_queue_的头部,同时将其增加到空闲队列free_queue_中。

           当调用模板类的方法ACE_Select_Reactor_T<ACE_SELECT_REACTOR_TOKEN>::register_handler,在这里是ACE_Select_Reactor_T<ACE_Reactor_Token_T<ACE_Token> >::register_handler函数,该函数调用this->register_handler_i,进而调用ACE_Select_Reactor_Handler_Repository::bind函数,该类中定义成员变量map_type event_handlers_;。而map_type类型则在类头部用typedef关键字定义,如果是ACE_WIN32平台则定义为模板类ACE_Hash_Map_Manager_Ex的某个实例,否则定义为ACE_Array_Base<ACE_Event_Handler*>。在ACE_Select_Reactor_Handler_Repository::open函数中如果是ACE_WIN32平台,调用this->event_handlers_.open函数,否则调用this->event_handlers_.size函数,这个地方一开始想当然,以为模板类ACE_Hash_Map_Manager_Ex也定义了size函数,后来才明白这个是模板类ACE_Array_Base中定义的函数。

           模板类ACE_Select_Reactor_T的构造函数中调用其open成员函数,因为该模板类的基类ACE_Select_Reactor_Impl中定义成员变量ACE_Select_Reactor_Handler_Repository handler_rep_;,所以在该函数中执行this->handler_rep_.open来调用ACE_Select_Reactor_Handler_Repository::open函数,在该函数中执行this->event_handlers_.open即调用ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::open函数。模板类ACE_Hash_Map_Manager_Ex的这个open方法中根据传递的参数1024调用其成员函数create_buckets,这个1024即模板类ACE_Select_Reactor_T的构造函数中指定的ACE_Select_Reactor_T<ACE_SELECT_REACTOR_TOKEN>::DEFAULT_SIZE,即模板类的基类ACE_Select_Reactor_Impl中定义的枚举变量。

           模板类ACE_Hash_Map_Manager_Ex的对象event_handlers_作为ACE_Select_Reactor_Handler_Repository类的成员变量。文件aceHash_Map_Manager_T.cpp中的ACE_Select_Reactor_Handler_Repository::open函数执行了两次,一次是在类构造函数中被调用,一次是ACE_Select_Reactor_Handler_Repository::open函数中执行(this->event_handlers_.open语句。ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::open函数首先调用close_i成员函数,然后再调用create_buckets成员函数。调用close_i成员函数的注释为(Calling this->close_i () to ensure we release previous allocated memory before allocating new one.)。create_buckets函数首先分配1024个ACE_Hash_Map_Entry大小的空间,模板类ACE_Hash_Map_Manager_Ex的成员变量ACE_Hash_Map_Entry<EXT_ID, INT_ID> *table_;指向这个空间,然后for循环创建ACE_Hash_Map_Entry<EXT_ID, INT_ID>对象,ACE_Hash_Map_Entry模板类包含成员变量ACE_Hash_Map_Entry<EXT_ID, INT_ID> *next_;、ACE_Hash_Map_Entry<EXT_ID, INT_ID> *prev_;此处的构造函数中将这两个指针赋值为指向自己。

           模板类ACE_Hash_Map_Manager_Ex的close_i函数会先判断类成员变量ACE_Hash_Map_Entry<EXT_ID, INT_ID> *table_;是否为空,如果不空则调用成员函数this->unbind_all_i(),该函数中外层for循环遍历成员变量table_的每一个元素,因为每一个元素都为ACE_Hash_Map_Entry对象,而该类包含了指向下一个对象的成员变量ACE_Hash_Map_Entry<EXT_ID, INT_ID> *next_;所以内层for循环进行遍历删除。两层for循环可以看成是宽度不等的不规则二维数组形式。close_i函数调用完this->unbind_all_i ()(//Remove all the entries.),再for循环遍历entr析构掉create_buckets函数中创建的entry即入口(//Iterate through the buckets cleaning up the sentinels.)、(//Destroy the dummy entry.)。create_buckets函数中for循环创建ACE_Hash_Map_Entry对象(//初始化hash表中每个入口为在头部带有作为哨兵的虚假结点的环形链)。

           调用ACE_Select_Reactor_T类的register_handler函数,最终调用ACE_Select_Reactor_Handler_Repository::bind函数,该函数调用模板类ACE_Hash_Map_Manager_Ex的bind函数,进而调用其成员函数bind_i,该函数中调用执行this->shared_find,在ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::shared_find函数中,先调用执行this->hash函数获取hash值,HASH_KEY hash_key_;作为模板类的成员变量,注释为(//Function object used for hashing keys.)。HASH_KEY是模板类ACE_Hash_Map_Manager_Ex的第三个模板参数,在这里为 ACE_Hash<void *>,由注释可知,hash_key_作为函数对象,其类型ACE_Hash<void *>一定重载了函数运算符(),具体的函数定义是在aceFunctor.inl文件中,在aceFunctor_T.h文件中声明模板类ACE_Hash,对该模板的特化声明在aceFunctor.h文件和aceFunctor_String.h文件中,对应的cpp文件中进行函数实现。 

           函数shared_find中调用this->hash获取到相应的hash值后会进行hash查找,从这个函数可以看到就算没有查到,也会通过引用参数把对应该项的hash位置返回给调用函数处。此处即ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::bind_i函数中,如果没有找到就分配空间创建一个ACE_Hash_Map_Entry对象,然后将当前项插入到给定位置的环形链的开头。

           在aceTime_Value.h头文件中对ACE_Time_Value类定义了前自增和后自增运算符,在对应的cpp文件中进行实现,实现文件中对前自增进行实现,前自增返回类型为引用类型,而且是返回自己所以用return *this;来实现;后自增的函数实现中先ACE_Time_Value tv (*this);构造返回值,然后调用前自增的实现,然后return tv;返回。

           在aceSelect_Reactor_Base.cpp文件中定义了ACE_Select_Reactor_Handler_Repository_Iterator类的实现,该类包含成员变量map_type event_handlers_;(//Underlying table of event handlers.),map_type为类内部typedef关键字声明的模板类ACE_Hash_Map_Manager_Ex的某一具体实例化类型。在类ACE_Select_Reactor_Handler_Repository_Iterator的实现中对成员变量event_handlers_的操作多是调用其begin()和end()函数。模板类ACE_Hash_Map_Manager_Ex的这两个函数返回ACE_Hash_Map_Iterator_Ex模板类对象,根据名字可知该类类似于标准库容器的一个迭代器,该类的构造函数中tail参数默认为0,默认构造的正向迭代器,如果调用ACE_Hash_Map_Manager_Ex模板类的end()函数则传递1来构造该对象,表示构造的是反响迭代器。

           模板类ACE_Hash_Map_Iterator_Ex继承自模板类ACE_Hash_Map_Iterator_Base_Ex,在ACE_Hash_Map_Iterator_Ex模板类的构造函数中会判断如果是返回CE_Hash_Map_Manager_Ex模板类的正向迭代器,即调用CE_Hash_Map_Manager_Ex模板类的begin函数,则会调用this->forward_i函数,该函数继承自其父模板类,在ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::forward_i函数中,会对其成员变量ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> *map_man_;(//Map we are iterating over.)进行操作。主要就是如名字所述往前移动一个位置,该函数的注释为(//Move forward by one element in the set.)。

  • 相关阅读:
    Linux sed命令实例详解
    hadoop2.0 和1.0的区别
    linux如何修改主机名
    hadoop主节点(NameNode)备份策略以及恢复方法
    Hadoop 添加删除数据节点(datanode)
    Hadoop常见错误及处理方法
    【转】ImageView.ScaleType属性
    MonoBehaviour.print和Debug.Log是同样的作用
    unity自带寻路Navmesh入门教程
    前向渲染路径细节 Forward Rendering Path Details
  • 原文地址:https://www.cnblogs.com/wongdu2014/p/7241150.html
Copyright © 2011-2022 走看看