ACE handle_timeout 事件重入
当多线程运行反应器事件时, 注意handle_timeout会重入,单独线程不存在下列问题!
1. 一个timer事件
// test_ace_timer.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "ace/Time_Value.h" #include "ace/Log_Msg.h" #include "ace/Synch.h" #include "ace/Reactor.h" #include "ace/Event_Handler.h" #include "ace/Dev_Poll_Reactor.h" #include "ace/Thread_Manager.h" #include <ace/Dev_Poll_Reactor.h> #include "ace/TP_Reactor.h" long timer10 = 0; long timer15 = 0; class Timer_Handler : public ACE_Event_Handler { public: virtual int handle_timeout(const ACE_Time_Value ¤t_time, const void *act /* = 0 */) { const int *num = ACE_static_cast(const int*,act); ACE_DEBUG((LM_INFO, ACE_TEXT("time: %d in --------\n"),num)); int n = 0 ; for (int i=0; i < 50000000; i++) { n++; } ACE_DEBUG((LM_INFO, ACE_TEXT("time: %d out ###########\n"),num)); return 0; } protected: private: }; ACE_THR_FUNC_RETURN thread_func(void *arg) { ACE_TRACE("thread_func(void *)"); ACE_Reactor::instance()->run_reactor_event_loop(); return 0; } int Start() { // Create a reactor from a tp reactor. ACE_TP_Reactor reactor_impl; ACE_Reactor reactor(&reactor_impl); ACE_Reactor::instance(&reactor); // Spawn some threads which run the reactor event loop(s) ACE_Thread_Manager::instance()->spawn_n(5, thread_func, 0, THR_NEW_LWP | THR_JOINABLE | THR_SCHED_RR); //ACE_Thread_Manager::instance()->spawn_n(1, thread_func, 0, THR_NEW_LWP | THR_JOINABLE | THR_SCHED_RR); Timer_Handler *timer = new Timer_Handler; ACE_Time_Value time_delay1(0, 10); //10ms ACE_Time_Value time_delay2(0, 15); //15ms timer10 = ACE_Reactor::instance()->schedule_timer(timer, (void *)&timer10, time_delay1, time_delay1); //timer15 = ACE_Reactor::instance()->schedule_timer(timer, (void *)&timer15, time_delay2, time_delay2); // Let the thread manager wait for all threads ACE_Thread_Manager::instance()->wait(); return 0; } int ACE_TMAIN(int argc, ACE_TCHAR *argv[]) { // Make sure we ignore SIGPIPE. Start(); // Parse arguments. return 0; }
测试结果:
time_out事件多次被调用, 此时可以改用一次性超时规避此问题,在启用timer任务时,handle_timeout分别改为调用下面这句。
timer10 = ACE_Reactor::instance()->schedule_timer(timer, (void *)&timer10, time_delay1);
2.多个timer事件
每个都注册一次性timer, 下列代码handle_timeout会重入, 若是存在其他共享资源,则有问题。
避免这样问题,如是多个timer, 可加锁处理。
// test_ace_timer.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "ace/Time_Value.h" #include "ace/Log_Msg.h" #include "ace/Synch.h" #include "ace/Reactor.h" #include "ace/Event_Handler.h" #include "ace/Dev_Poll_Reactor.h" #include "ace/Thread_Manager.h" #include <ace/Dev_Poll_Reactor.h> #include "ace/TP_Reactor.h" class Timer_Handler; long timer10 = 0; long timer15 = 0; ACE_Time_Value time_delay1(0, 10); ACE_Time_Value time_delay2(0, 15); Timer_Handler *timer = NULL; class Timer_Handler : public ACE_Event_Handler { public: virtual int handle_timeout(const ACE_Time_Value ¤t_time, const void *act /* = 0 */) { const int *num = ACE_static_cast(const int*,act); ACE_DEBUG((LM_INFO, ACE_TEXT("time: %d in --------\n"),*num)); int n = 0 ; for (int i=0; i < 50000000; i++) { n++; } ACE_DEBUG((LM_INFO, ACE_TEXT("time: %d out ###########\n"),*num)); if (*num == timer10) { timer10 = ACE_Reactor::instance()->schedule_timer(timer, (void *)&timer10, time_delay1); } else if(*num == timer15) { timer15 = ACE_Reactor::instance()->schedule_timer(timer, (void *)&timer15, time_delay2); } return 0; } protected: private: }; ACE_THR_FUNC_RETURN thread_func(void *arg) { ACE_TRACE("thread_func(void *)"); ACE_Reactor::instance()->run_reactor_event_loop(); return 0; } int Start() { // Create a reactor from a tp reactor. ACE_TP_Reactor reactor_impl; ACE_Reactor reactor(&reactor_impl); ACE_Reactor::instance(&reactor); // Spawn some threads which run the reactor event loop(s) ACE_Thread_Manager::instance()->spawn_n(5, thread_func, 0, THR_NEW_LWP | THR_JOINABLE | THR_SCHED_RR); //ACE_Thread_Manager::instance()->spawn_n(1, thread_func, 0, THR_NEW_LWP | THR_JOINABLE | THR_SCHED_RR); timer = new Timer_Handler; timer10 = ACE_Reactor::instance()->schedule_timer(timer, (void *)&timer10, time_delay1); timer15 = ACE_Reactor::instance()->schedule_timer(timer, (void *)&timer15, time_delay2); // Let the thread manager wait for all threads ACE_Thread_Manager::instance()->wait(); return 0; } int ACE_TMAIN(int argc, ACE_TCHAR *argv[]) { // Make sure we ignore SIGPIPE. Start(); // Parse arguments. return 0; }
测试结果: