Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1061456
  • 博文数量: 264
  • 博客积分: 6005
  • 博客等级: 大校
  • 技术积分: 2798
  • 用 户 组: 普通用户
  • 注册时间: 2007-08-08 20:15
文章分类

全部博文(264)

文章存档

2011年(42)

2010年(213)

2009年(4)

2008年(2)

2007年(3)

分类: C/C++

2011-06-20 23:04:14


这个类的接口与QTimer类似,能对现有代码改动极小的情况下取代QTimer

这个类使用linux上的timer_*系统调用实现,只能用于linux平台,但使用boost:signals2实现了类似Qt的信号回调机制。

编写这个类本意是学习一下boost的信号机制,没想到测试效果非常好,达到完成替代QTimer类的功能,在此列出,

  1. #ifndef NBTIMER_H
  2. #define NBTIMER_H
  3.  
  4. #include <signal.h>
  5. #include <sys/time.h>
  6.  
  7. #include "boost/signals2.hpp"
  8.  
  9. #define NBSLOT(mf,obj) boost::bind(&mf,obj)
  10. #define NBSLOT1(mf,obj) boost::bind(&mf,obj,_1)
  11. #define NBSLOT2(mf,obj) boost::bind(&mf,obj,_1,_2)
  12. #define NBSLOT3(mf,obj) boost::bind(&mf,obj,_1,_2,_3)
  13. #define NBSLOT4(mf,obj) boost::bind(&mf,obj,_1,_2,_3,_4)
  14. #define NBSLOT5(mf,obj) boost::bind(&mf,obj,_1,_2,_3,_4,_5)
  15. #define NBSLOT6(mf,obj) boost::bind(&mf,obj,_1,_2,_3,_4,_5,_6)
  16. #define NBSLOT7(mf,obj) boost::bind(&mf,obj,_1,_2,_3,_4,_5,_6,_7)
  17. #define NBSLOT8(mf,obj) boost::bind(&mf,obj,_1,_2,_3,_4,_5,_6,_7,_8)
  18. #define NBSLOT9(mf,obj) boost::bind(&mf,obj,_1,_2,_3,_4,_5,_6,_7,_8,_9)
  19.  
  20. class MyTimer
  21. {
  22.  public:
  23.     MyTimer();
  24.     virtual ~MyTimer();
  25.  
  26.     void start(int msec);
  27.     void start();
  28.     void stop();
  29.     int interval() {return this->m_intval;}
  30.     void setInterval(int msec);
  31.     bool isSingleShot() { return this->m_is_single_shot; }
  32.     bool isActive() {return this->m_started; }
  33.  
  34.     boost::signals2::connection connect(boost::signals2::signal<void ()>::slot_type slot);
  35.  
  36.     static void singleShot(int msec, boost::signals2::signal<void ()>::slot_type slot);
  37.  
  38.  public:
  39.     static void sig_timeout_handler(int sig, siginfo_t *si, void *uc);
  40.     static void print_siginfo(siginfo_t *si);
  41.  
  42.     static void sig_timeout_revoke_back1(siginfo_t *si);
  43.     void sig_timeout_revoke_back2();
  44.  
  45.  public: // signals
  46.     boost::signals2::signal<void ()> sig_timeout;
  47.  
  48.  protected:
  49.     MyTimer(bool single);
  50.     void init_timer_signal();
  51.  
  52.  private:
  53.     timer_t m_timer_id;
  54.     int m_intval;
  55.     struct sigevent m_sev;
  56.     bool m_started;
  57.     bool m_is_single_shot;
  58.     static constexpr timer_t INV_TIMER_ID = NULL;
  59. };
  60.  
  61. #endif

  62. #include "mytimer.h"
  63.  
  64. MyTimer::MyTimer()
  65. {
  66.     this->m_timer_id = MyTimer::INV_TIMER_ID;
  67.     this->m_intval = 0;
  68.     this->m_started = false;
  69.     this->m_is_single_shot = false;
  70.     // printf("====%d\n", this->m_timer_id == MyTimer::INV_TIMER_ID);
  71. }
  72.  
  73. MyTimer::MyTimer(bool single)
  74. {
  75.     new(this)MyTimer();
  76.     this->m_is_single_shot = true;
  77. }
  78.  
  79. MyTimer::~MyTimer()
  80. {
  81.     if (this->m_timer_id != MyTimer::INV_TIMER_ID) {
  82.         timer_delete(this->m_timer_id);
  83.     }
  84. }
  85. // timer_t MyTimer::INV_TIMER_ID = NULL;
  86.  
  87. void MyTimer::start(int msec)
  88. {
  89.     this->m_intval = msec;
  90.  
  91.     if (this->m_timer_id == MyTimer::INV_TIMER_ID) {
  92.         this->init_timer_signal();
  93.     }
  94.  
  95.     if (!this->m_started) {
  96.         this->start();
  97.     }
  98. }
  99.  
  100. void MyTimer::start()
  101. {
  102.     int iret;
  103.  
  104.     if (this->m_timer_id == MyTimer::INV_TIMER_ID) {
  105.         this->init_timer_signal();
  106.     }
  107.  
  108.     if (!this->m_started) {
  109.         struct itimerspec itspec, oitspec;
  110.         memset(&itspec, 0, sizeof(itspec));
  111.         itspec.it_interval.tv_sec = this->m_intval / 1000;
  112.         itspec.it_interval.tv_nsec = (this->m_intval % 1000) * 1000000;
  113.         // itspec.it_interval.tv_sec = 2;
  114.         // itspec.it_interval.tv_nsec = 0;
  115.  
  116.         itspec.it_value.tv_sec = itspec.it_interval.tv_sec;
  117.         itspec.it_value.tv_nsec = itspec.it_interval.tv_nsec;
  118.  
  119.         printf("sec: %ld, nsec: %ld\n", itspec.it_interval.tv_sec, itspec.it_interval.tv_nsec);
  120.  
  121.         memset(&oitspec, 0, sizeof(oitspec));
  122.  
  123.         iret = timer_settime(this->m_timer_id, 0, &itspec, NULL);
  124.         if (iret == -1) {
  125.             perror("set error");
  126.             // assert(iret != -1);
  127.         }
  128.  
  129.         this->m_started = true;
  130.     }
  131. }
  132.  
  133. void MyTimer::stop()
  134. {
  135.     int iret = 0;
  136.     if (this->m_timer_id != MyTimer::INV_TIMER_ID) {
  137.         struct itimerspec itspec, oitspec;
  138.         memset(&itspec, 0, sizeof(struct itimerspec));
  139.         memset(&oitspec, 0, sizeof(struct itimerspec));
  140.  
  141.         iret = timer_settime(this->m_timer_id, 0, &itspec, &oitspec);
  142.         if (iret == -1) {
  143.             perror("set timer stop error");
  144.         }
  145.     }
  146. }
  147.  
  148. void MyTimer::setInterval(int msec)
  149. {
  150.     this->m_intval = msec;
  151. }
  152.  
  153. void MyTimer::init_timer_signal()
  154. {
  155.     int iret = 0;
  156.     sigset_t mask;
  157.     struct sigaction sa;
  158.  
  159.     sa.sa_flags = SA_SIGINFO;
  160.     // sa.sa_sigaction = sig_timer_handler;
  161.     // sa.sa_sigaction = MyTimer::sig_timeout_handler;
  162.     sa.sa_sigaction = MyTimer::sig_timeout_handler;
  163.     sigemptyset(&sa.sa_mask);
  164.     iret = sigaction(SIGRTMIN, &sa, NULL);
  165.     assert(iret != -1);
  166.  
  167.     sigemptyset(&mask);
  168.     sigaddset(&mask, SIGRTMIN);
  169.     // iret = sigprocmask(SIG_SETMASK, &mask, NULL);
  170.  
  171.     this->m_sev.sigev_notify = SIGEV_SIGNAL;
  172.     this->m_sev.sigev_signo = SIGRTMIN;
  173.     // this->m_sev.sigev_value.sival_ptr = &this->m_timer_id;
  174.     this->m_sev.sigev_value.sival_ptr = this;
  175.     iret = timer_create(CLOCK_REALTIME, &this->m_sev, &this->m_timer_id);
  176.     printf("timer:%p\n", this->m_timer_id);
  177.     assert(iret != -1);
  178.  
  179. }
  180.  
  181. // #include "boost/lambda/lambda.hpp"
  182. // #include "boost/lambda/bind.hpp"
  183. // #include "boost/lambda/if.hpp"
  184.  
  185. struct abcde {
  186.     void operator()(int a) {
  187.         printf("ahaha: %d\n", a);
  188.     }
  189. };
  190.  
  191. boost::signals2::connection MyTimer::connect(boost::signals2::signal<void ()>::slot_type slot)
  192. {
  193.     boost::signals2::connection conn;
  194.  
  195.     conn = this->sig_timeout.connect(slot);
  196.  
  197.     return conn;
  198.  
  199.     boost::function<void(void)> onClick;
  200.  
  201.     // ok
  202.     onClick = slot;
  203.  
  204.     // ok
  205.     onClick = {
  206.     };
  207.     onClick();
  208.  
  209.     // ok
  210.     onClick = slot;
  211.  
  212.     boost::function<void(int)> onChange;
  213.  
  214.     // ok
  215.     onChange = abcde();
  216.  
  217.     // onChange = (std::cout<< boost::lambda::_1 <<" "<<boost::lambda::_1);
  218.     // (std::cout<< boost::lambda::_1 << boost::lambda::_3 << boost::lambda::_2)("adf","fd","dfd");
  219.  
  220.     [](int x) -> int {
  221.         return x + 6;
  222.     };
  223.  
  224.     int x = 5;
  225.     char *y = NULL;
  226.     std::string z;
  227.  
  228.     [=](int x) -> int {
  229.         if (y == NULL) {
  230.         }
  231.         return x + 6;
  232.     };
  233.  
  234.     [&](int x) -> int {
  235.         if (y == NULL) {
  236.         }
  237.         return x + 6;
  238.     };
  239.  
  240.     [&y,&z](int x) -> int {
  241.         if (y == NULL) {
  242.         }
  243.         return x + 6;
  244.     };
  245.  
  246.     auto my_lambda_func = [&](int x) { /*...*/ };
  247.     auto my_onheap_lambda_func = new auto([=](int x) { /*...*/ });
  248.     my_lambda_func(5);
  249.     (*my_onheap_lambda_func)(6);
  250.  
  251.     using namespace std;
  252.     vector<int> v = {50, -10, 20, -30};
  253.  
  254.     // gcc version problem, go to gcc 4.6.0 now
  255.     std::sort(v.begin(), v.end(), [](int a, int b) { return abs(a)<abs(b); });
  256.  
  257.     struct BasicStruct {
  258.         int x;
  259.         double y;
  260.     };
  261.  
  262.     struct AltStruct {
  263.         AltStruct(int x, double y) : x_{x}, y_{y} {}
  264.  
  265.     private:
  266.         int x_;
  267.         double y_;
  268.     };
  269.  
  270.     BasicStruct var1{5, 3.2};
  271.     AltStruct var2{2, 4.3};
  272.  
  273. }
  274.  
  275. // static
  276. void MyTimer::singleShot(int msec, boost::signals2::signal<void ()>::slot_type slot)
  277. {
  278.     MyTimer *t = new MyTimer(true);
  279.     t->setInterval(msec);
  280.     t->connect(slot);
  281.     t->start();
  282. }
  283.  
  284. // static
  285. void MyTimer::sig_timeout_handler(int sig, siginfo_t *si, void *uc)
  286. {
  287.     /* Note: calling printf() from a signal handler is not
  288.        strictly correct, since printf() is not async-signal-safe;
  289.        see signal(7) */
  290.  
  291.     printf("Caught signal %d\n", sig);
  292.     [] (siginfo_t*si) {
  293.         // MyTimer::print_siginfo(si);
  294.         MyTimer::print_siginfo(si);
  295.     } (si);
  296.  
  297.  
  298.     MyTimer::sig_timeout_revoke_back1(si);
  299.     // signal(sig, SIG_IGN);
  300. }
  301.  
  302. // static
  303. void MyTimer::print_siginfo(siginfo_t *si)
  304. {
  305.     timer_t *tidp;
  306.     int oret;
  307.  
  308.     // tidp = (timer_t*)si->si_value.sival_ptr;
  309.  
  310.     // printf(" sival_ptr = %p; ", si->si_value.sival_ptr);
  311.     // printf(" *sival_ptr = 0x%lx\n", (long) *tidp);
  312.  
  313.     // oret = timer_getoverrun(*tidp);
  314.     // if (oret == -1) {
  315.     // perror("timer_getoverrun");
  316.     // }
  317.     // else
  318.     // printf(" overrun count = %d\n", oret);
  319.  
  320.  
  321. }
  322.  
  323. // static
  324. void MyTimer::sig_timeout_revoke_back1(siginfo_t *si)
  325. {
  326.     MyTimer *t = NULL;
  327.  
  328.     t = (MyTimer*)si->si_value.sival_ptr;
  329.     t->sig_timeout_revoke_back2();
  330. }
  331.  
  332. void MyTimer::sig_timeout_revoke_back2()
  333. {
  334.     printf("sig timeout arrived:\n");
  335.     this->sig_timeout();
  336.     if (this->m_is_single_shot) {
  337.         this->stop();
  338.         delete this;
  339.     }
  340. }
阅读(2946) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~