使用C++0x与boost编写的异步信号回调计时器类 |
发布: 2011-04-15 11:45 |
这个类的接口与QTimer类似,能对现有代码改动极小的情况下取代QTimer 这个类使用linux上的timer_*系统调用实现,只能用于linux平台,但使用boost:signals2实现了类似Qt的信号回调机制。 编写这个类本意是学习一下boost的信号机制,没想到测试效果非常好,达到完成替代QTimer类的功能,在此列出, [code type="cpp"] #ifndef NBTIMER_H #define NBTIMER_H #include #include #include "boost/signals2.hpp" #define NBSLOT(mf,obj) boost::bind(&mf,obj) #define NBSLOT1(mf,obj) boost::bind(&mf,obj,_1) #define NBSLOT2(mf,obj) boost::bind(&mf,obj,_1,_2) #define NBSLOT3(mf,obj) boost::bind(&mf,obj,_1,_2,_3) #define NBSLOT4(mf,obj) boost::bind(&mf,obj,_1,_2,_3,_4) #define NBSLOT5(mf,obj) boost::bind(&mf,obj,_1,_2,_3,_4,_5) #define NBSLOT6(mf,obj) boost::bind(&mf,obj,_1,_2,_3,_4,_5,_6) #define NBSLOT7(mf,obj) boost::bind(&mf,obj,_1,_2,_3,_4,_5,_6,_7) #define NBSLOT8(mf,obj) boost::bind(&mf,obj,_1,_2,_3,_4,_5,_6,_7,_8) #define NBSLOT9(mf,obj) boost::bind(&mf,obj,_1,_2,_3,_4,_5,_6,_7,_8,_9) class MyTimer { public: MyTimer(); virtual ~MyTimer(); void start(int msec); void start(); void stop(); int interval() {return this->m_intval;} void setInterval(int msec); bool isSingleShot() { return this->m_is_single_shot; } bool isActive() {return this->m_started; } boost::signals2::connection connect(boost::signals2::signal static void singleShot(int msec, boost::signals2::signal public: static void sig_timeout_handler(int sig, siginfo_t *si, void *uc); static void print_siginfo(siginfo_t *si); static void sig_timeout_revoke_back1(siginfo_t *si); void sig_timeout_revoke_back2(); public: // signals boost::signals2::signal protected: MyTimer(bool single); void init_timer_signal(); private: timer_t m_timer_id; int m_intval; struct sigevent m_sev; bool m_started; bool m_is_single_shot; static constexpr timer_t INV_TIMER_ID = NULL; }; #endif [/code] [code type="cpp"] #include "mytimer.h" MyTimer::MyTimer() { this->m_timer_id = MyTimer::INV_TIMER_ID; this->m_intval = 0; this->m_started = false; this->m_is_single_shot = false; // printf("====%d\n", this->m_timer_id == MyTimer::INV_TIMER_ID); } MyTimer::MyTimer(bool single) { new(this)MyTimer(); this->m_is_single_shot = true; } MyTimer::~MyTimer() { if (this->m_timer_id != MyTimer::INV_TIMER_ID) { timer_delete(this->m_timer_id); } } // timer_t MyTimer::INV_TIMER_ID = NULL; void MyTimer::start(int msec) { this->m_intval = msec; if (this->m_timer_id == MyTimer::INV_TIMER_ID) { this->init_timer_signal(); } if (!this->m_started) { this->start(); } } void MyTimer::start() { int iret; if (this->m_timer_id == MyTimer::INV_TIMER_ID) { this->init_timer_signal(); } if (!this->m_started) { struct itimerspec itspec, oitspec; memset(&itspec, 0, sizeof(itspec)); itspec.it_interval.tv_sec = this->m_intval / 1000; itspec.it_interval.tv_nsec = (this->m_intval % 1000) * 1000000; // itspec.it_interval.tv_sec = 2; // itspec.it_interval.tv_nsec = 0; itspec.it_value.tv_sec = itspec.it_interval.tv_sec; itspec.it_value.tv_nsec = itspec.it_interval.tv_nsec; printf("sec: %ld, nsec: %ld\n", itspec.it_interval.tv_sec, itspec.it_interval.tv_nsec); memset(&oitspec, 0, sizeof(oitspec)); iret = timer_settime(this->m_timer_id, 0, &itspec, NULL); if (iret == -1) { perror("set error"); // assert(iret != -1); } this->m_started = true; } } void MyTimer::stop() { int iret = 0; if (this->m_timer_id != MyTimer::INV_TIMER_ID) { struct itimerspec itspec, oitspec; memset(&itspec, 0, sizeof(struct itimerspec)); memset(&oitspec, 0, sizeof(struct itimerspec)); iret = timer_settime(this->m_timer_id, 0, &itspec, &oitspec); if (iret == -1) { perror("set timer stop error"); } } } void MyTimer::setInterval(int msec) { this->m_intval = msec; } void MyTimer::init_timer_signal() { int iret = 0; sigset_t mask; struct sigaction sa; sa.sa_flags = SA_SIGINFO; // sa.sa_sigaction = sig_timer_handler; // sa.sa_sigaction = MyTimer::sig_timeout_handler; sa.sa_sigaction = MyTimer::sig_timeout_handler; sigemptyset(&sa.sa_mask); iret = sigaction(SIGRTMIN, &sa, NULL); assert(iret != -1); sigemptyset(&mask); sigaddset(&mask, SIGRTMIN); // iret = sigprocmask(SIG_SETMASK, &mask, NULL); this->m_sev.sigev_notify = SIGEV_SIGNAL; this->m_sev.sigev_signo = SIGRTMIN; // this->m_sev.sigev_value.sival_ptr = &this->m_timer_id; this->m_sev.sigev_value.sival_ptr = this; iret = timer_create(CLOCK_REALTIME, &this->m_sev, &this->m_timer_id); printf("timer:%p\n", this->m_timer_id); assert(iret != -1); } // #include "boost/lambda/lambda.hpp" // #include "boost/lambda/bind.hpp" // #include "boost/lambda/if.hpp" struct abcde { void operator()(int a) { printf("ahaha: %d\n", a); } }; boost::signals2::connection MyTimer::connect(boost::signals2::signal { boost::signals2::connection conn; conn = this->sig_timeout.connect(slot); return conn; boost::function // ok onClick = slot; // ok onClick = { }; onClick(); // ok onClick = slot; boost::function // ok onChange = abcde(); // onChange = (std::cout<< boost::lambda::_1 <<" "< [](int x) -> int { return x + 6; }; int x = 5; char *y = NULL; std::string z; [=](int x) -> int { if (y == NULL) { } return x + 6; }; [&](int x) -> int { if (y == NULL) { } return x + 6; }; [&y,&z](int x) -> int { if (y == NULL) { } return x + 6; }; auto my_lambda_func = [&](int x) { /*...*/ }; auto my_onheap_lambda_func = new auto([=](int x) { /*...*/ }); my_lambda_func(5); (*my_onheap_lambda_func)(6); using namespace std; vector // gcc version problem, go to gcc 4.6.0 now std::sort(v.begin(), v.end(), [](int a, int b) { return abs(a) struct BasicStruct { int x; double y; }; struct AltStruct { AltStruct(int x, double y) : x_{x}, y_{y} {} private: int x_; double y_; }; BasicStruct var1{5, 3.2}; AltStruct var2{2, 4.3}; } // static void MyTimer::singleShot(int msec, boost::signals2::signal { MyTimer *t = new MyTimer(true); t->setInterval(msec); t->connect(slot); t->start(); } // static void MyTimer::sig_timeout_handler(int sig, siginfo_t *si, void *uc) { /* Note: calling printf() from a signal handler is not strictly correct, since printf() is not async-signal-safe; see signal(7) */ printf("Caught signal %d\n", sig); [] (siginfo_t*si) { // MyTimer::print_siginfo(si); MyTimer::print_siginfo(si); } (si); MyTimer::sig_timeout_revoke_back1(si); // signal(sig, SIG_IGN); } // static void MyTimer::print_siginfo(siginfo_t *si) { timer_t *tidp; int oret; // tidp = (timer_t*)si->si_value.sival_ptr; // printf(" sival_ptr = %p; ", si->si_value.sival_ptr); // printf(" *sival_ptr = 0x%lx\n", (long) *tidp); // oret = timer_getoverrun(*tidp); // if (oret == -1) { // perror("timer_getoverrun"); // } // else // printf(" overrun count = %d\n", oret); } // static void MyTimer::sig_timeout_revoke_back1(siginfo_t *si) { MyTimer *t = NULL; t = (MyTimer*)si->si_value.sival_ptr; t->sig_timeout_revoke_back2(); } void MyTimer::sig_timeout_revoke_back2() { printf("sig timeout arrived:\n"); this->sig_timeout(); if (this->m_is_single_shot) { this->stop(); delete this; } } [/code] |
原文: http://qtchina.tk/?q=node/570 |
Powered by zexport
|