timer定时器,多线程,回调为阻塞模式。支持参数绑定,非常好使。
用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | ////////////////////////////////////////////////////////////////////////// //以下是测试代码 namespace timertester { class timertestclass { public : timertestclass(){}; ~timertestclass(){}; void testfn() { printf ( "timer callback is class func.\n" ); FTimerEvent mTimer(3000, &timertestclass::threadfn, this ); for ( int i = 0; i < 5; i++) { printf ( "press any key to ...\n" ); getchar (); mTimer.SetTimerEvent(); } printf ( "stop timer \n" ); mTimer.StopTimer(); } void threadf( int i) { printf ( "test f i:%d\n" , i); } void threadfn() { printf ( "test fn d\n" ); } void threadfn2() { printf ( "test fn2222 \n" ); } }; static void testfn1(timertestclass *cls) { cls->threadfn(); } static void testpf() { printf ( "test printf \n" ); printf ( "callback ret. \n" ); } static void prt( int & i) { printf ( "print %d\n" , i); } static void timertest() { int t = 0; FTimerEvent timerstdref(1000, prt, std::ref(t)); for ( int i = 0; i < 10; i++) { t = i; Sleep(1000); } timerstdref.StopTimer(); { printf ( "timer 0 manual to set\n" ); //如果定时为0,则每次为手动触发 FTimerEvent timerman(0, [](){ printf ( "timerman in.\n" ); Sleep(5000); printf ( "timerman out.\n" ); }); timerman.SetTimerEvent(); timerman.SetTimerEvent(); timerman.StopTimer(); } printf ( "stop timer in callback\n" ); FTimerEvent timer4; timer4.InitTimer(1000, [](FTimerEvent *pTimer){ printf ( "exit timer\n" ); pTimer->StopTimer(); }, &timer4); Sleep(3000); timer4.StopTimer(); printf ( "set timer in callback\n" ); FTimerEvent timer5; timer5.InitTimer(2000, [](FTimerEvent *pTimer){ static bool set = false ; printf ( "timer in\n" ); if (!set) { printf ( "set timer\n" ); pTimer->SetTimerEvent(); set = true ; } printf ( "timer out\n" ); }, &timer5); Sleep(10000); timer5.StopTimer(); timertestclass test1; test1.testfn(); int x = 0; FTimerEvent timerref(1000, [&x]() { printf ( "x: %d \n" , x); }); for ( int i = 0; i < 10; i++) { x = i; Sleep(1000); } timerref.StopTimer(); FTimerEvent timerx(1000, [&test1]() { test1.threadfn2(); }); Sleep(10000); timerx.StopTimer(); FTimerEvent timer0(1000, testpf); Sleep(10000); timer0.StopTimer(); FTimerEvent timer1(1000, testfn1, &test1); Sleep(10000); timer1.StopTimer(); FTimerEvent timer2(1000, [](){ printf ( "lambada no param \n" ); }); Sleep(10000); timer2.StopTimer(); int param = 0; FTimerEvent timer3(1000, []( int *p){ printf ( "lambada with param: %d \n" , *p); }, ¶m); Sleep(10000); timer3.StopTimer(); } } |
Timer.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | #pragma once #include <thread> #include <functional> #include <chrono> #include <future> #include <mutex> #include <atomic> #include <condition_variable> class FTimerEvent { private : std::mutex m_mtx; std::condition_variable m_Condition; std::future< int > m_loopTask; std:: thread ::id m_loopThreadID; //回调函数 std::function< void ()> m_funCallback; //退出标记 bool m_bExit; std::atomic< int > m_nManual; void _InitTimer(uint32_t nTimeout) { m_nManual = 0; m_loopTask = std::async(std::launch::async, [ this , nTimeout]()-> int { printf ( "timer thread start...\n" ); //保存线程ID m_loopThreadID = std::this_thread::get_id(); while (!m_bExit || m_nManual) { //wait for timeout std::unique_lock<std::mutex> lock(m_mtx); //bool waitret = false; if (nTimeout) m_Condition.wait_for(lock, std::chrono::milliseconds(nTimeout), [ this ](){ return (m_nManual != 0); }); else m_Condition.wait(lock, [ this ](){ return (m_nManual != 0); }); if (m_bExit && m_nManual == 0) return 0; if (m_nManual) m_nManual--; //callback //printf("timer call back ... \n"); m_funCallback(); } printf ( "timer thread exit.\n" ); return 0; }); } public : //禁止拷贝和移动 FTimerEvent( const FTimerEvent&) = delete ; FTimerEvent& operator=( const FTimerEvent&) = delete ; //默认的构造函数 FTimerEvent(){ m_bExit = false ; }; //带参数的构造函数 template < class F, class ... Args> FTimerEvent(uint32_t dwTimeout, F&& f, Args&&... args) { m_bExit = false ; m_funCallback = std::bind(std::forward<F>(f), std::forward<Args>(args)...); _InitTimer(dwTimeout); } //如果使用默认构造函数定义的示例 可以手动初始化 不允许重复调用 template < class F, class ... Args> bool InitTimer(uint32_t dwTimeout, F&& f, Args&&... args) { assert (m_funCallback == nullptr); if (m_funCallback != nullptr) return false ; m_funCallback = std::bind(std::forward<F>(f), std::forward<Args>(args)...); _InitTimer(dwTimeout); return true ; } ~FTimerEvent( void ) { StopTimer(); printf ( "Timer has Stopped. \n" ); } //阻塞事件,会等所有的回调都完成后再退出 //如果在回调内部调用,会立即返回 void StopTimer() { if (!m_bExit) printf ( "Stop Timer \n" ); //stop flag m_bExit = true ; //通知一下阻塞事件 if (std::this_thread::get_id() != m_loopThreadID) { m_Condition.notify_one(); //等待线程退出 try { m_loopTask.get(); } catch (...){} } } //触发一次事件 异步返回 //必然触发的回调,哪怕调用了StopTimer也会把Set过的次数都回调一遍再退出 void SetTimerEvent() { m_nManual++; m_Condition.notify_one(); } }; |