調試C++NPv2_Select_Reactor_Log_Server程序

       調試C++NPv2_Select_Reactor_Log_Server程序,main函數中聲明變量ACE_Select_Reactor select_reactor;。在ace\Select_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中。node

       函數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的還有監聽套接口,在examples\C++NPv2\Logging_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函數。react

       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模型來監測觸發事件。ace\OS_NS_sys_select.inl文件中定義的ACE_OS::select函數的參數包含fd_set *類型,這裏調用以ACE_Handle_Set類型做爲實參,因此須要ACE_Handle_Set類的類型轉換。ace\OS_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。 oop

       模板類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_;。ui

       類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函數。this

       模板類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_;串起來。spa

       當調用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類的成員變量。文件ace\Hash_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 *>必定重載了函數運算符(),具體的函數定義是在ace\Functor.inl文件中,在ace\Functor_T.h文件中聲明模板類ACE_Hash,對該模板的特化聲明在ace\Functor.h文件和ace\Functor_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對象,而後將當前項插入到給定位置的環形鏈的開頭。

       在ace\Time_Value.h頭文件中對ACE_Time_Value類定義了前自增和後自增運算符,在對應的cpp文件中進行實現,實現文件中對前自增進行實現,前自增返回類型爲引用類型,並且是返回本身因此用return *this;來實現;後自增的函數實現中先ACE_Time_Value tv (*this);構造返回值,而後調用前自增的實現,而後return tv;返回。

       在ace\Select_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.)。

相關文章
相關標籤/搜索