博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux组件封装(六)——定时器的简单封装
阅读量:6167 次
发布时间:2019-06-21

本文共 7752 字,大约阅读时间需要 25 分钟。

在Linux中,有一种简单的定时器——timerfd,它通过查看fd是否可读来判断定时器时候到时。

timerfd中常用的函数有timerfd_create、timerfd_settime、timerfd_gettime,这些函数都相对简单,我们可以到man手册来查看用法。

值得注意的是:create中的参数CLOCK_REALTIME是一个相对时间,我们可以通过调整系统时间对其进行调整,而CLOCK_MONOTIC是一个绝对时间,系统时间的改变不会影响它。在create中,flags一般设置为0。

下面是一个简单的例子:

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #define ERR_EXIT(m) \11 do { \12 perror(m);\13 exit(EXIT_FAILURE);\14 }while(0)15 16 void foo()17 {18 printf("foo\n");19 }20 21 22 int main(int argc, const char *argv[])23 {24 //创建fd25 26 int timerfd = timerfd_create(CLOCK_REALTIME, 0);27 if(timerfd == -1)28 ERR_EXIT("timerfd_create");29 30 //设置时间31 struct itimerspec tv;32 memset(&tv, 0, sizeof tv);33 tv.it_value.tv_sec = 3;34 tv.it_interval.tv_sec = 1;35 if(timerfd_settime(timerfd, 0, &tv, NULL) == -1)36 ERR_EXIT("timerfd_settime");37 38 char buf[1024] = { 0}; 39 int ret; 40 while((ret = read(timerfd, buf, sizeof buf)) > 0){ 41 printf("ret = %d, read data:%s\n", ret, buf); // 42 } 43 44 close(timerfd);45 46 return 0;47 }
View Code

这里需要注意:一旦定时器到期,fd中就有数据可读,这个时候,我们一定要将fd中的数据read出来,否则定时器会产生异常,无法正常工作。

我们可以将timerfd和poll一起使用,将timerfd加入到poll的监听数组中,这样当timerfd可读时,我们就调用相应的函数,来完成定时任务。

然而当我们不将timerfd中的数据读出时,poll监听到timerfd一直可读,这样就会一直触发相应函数,就失去了定时器的左右。

所以,我们一定要注意将timerfd中的数据读出

将timerfd与poll结合:

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #define ERR_EXIT(m) \11 do { \12 perror(m);\13 exit(EXIT_FAILURE);\14 }while(0)15 16 void foo()17 {18 printf("foo\n");19 }20 21 22 int main(int argc, const char *argv[])23 {24 //创建fd25 26 int timerfd = timerfd_create(CLOCK_REALTIME, 0);27 if(timerfd == -1)28 ERR_EXIT("timerfd_create");29 30 //设置时间31 struct itimerspec tv;32 memset(&tv, 0, sizeof tv);33 tv.it_value.tv_sec = 3;34 tv.it_interval.tv_sec = 1;35 if(timerfd_settime(timerfd, 0, &tv, NULL) == -1)36 ERR_EXIT("timerfd_settime");37 38 //判断fd可读39 40 //int poll(struct pollfd *fds, nfds_t nfds, int timeout);41 42 struct pollfd pfd;43 pfd.fd = timerfd;44 pfd.events = POLLIN; //监听输入事件45 46 uint64_t val;47 int ret;48 while(1)49 {50 ret = poll(&pfd, 1, 5000);51 if(ret == -1)52 {53 if(errno == EINTR)54 continue;55 ERR_EXIT("poll");56 }57 else if(ret == 0)58 {59 printf("timeout\n"); //超时60 }61 62 if(pfd.revents == POLLIN) //此fd是否监听的read事件63 {64 read(timerfd, &val, sizeof val);65 foo();66 }67 68 }69 70 71 close(timerfd);72 73 return 0;74 }
View Code

我们可以将timerfd类的函数封装到一个Timer类中,提供一个接口来接受用户要执行的函数(即回调函数),这样做,可以使我们的定时器更加安全、实用。

声明代码如下:

1 #ifndef TIMER_H 2 #define TIMER_H 3 #include 
4 #include
5 #include
6 7 class Timer : boost::noncopyable 8 { 9 public:10 11 typedef std::function
TimerCallback;12 13 Timer(int val, int interval, TimerCallback cb);14 ~Timer();15 16 void start();17 void stop();18 19 private:20 21 int _timerfd;22 int _val;23 int _interval;24 TimerCallback _callback;25 bool _isStart;26 };27 28 29 30 #endif /*TIMER_H*/
View Code

实现代码如下:

1 #include "Timer.h"  2 #include 
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #define ERR_EXIT(m) \ 12 do { \ 13 perror(m);\ 14 exit(EXIT_FAILURE);\ 15 }while(0) 16 namespace 17 { 18 int createTimer() 19 { 20 int timerfd = ::timerfd_create(CLOCK_REALTIME, 0); 21 if(timerfd == -1) 22 ERR_EXIT("create"); 23 24 return timerfd; 25 } 26 27 void setTimer(int timerfd, int val, int interval) 28 { 29 struct itimerspec t; 30 memset(&t, 0, sizeof t); 31 t.it_value.tv_sec = val; 32 t.it_interval.tv_sec = interval; 33 34 if(::timerfd_settime(timerfd, 0, &t, NULL) == -1) 35 ERR_EXIT("settime"); 36 } 37 38 void stopTimer(int timerfd) 39 { 40 setTimer(timerfd, 0, 0); 41 } 42 43 void readTimer(int timerfd) 44 { 45 uint64_t howmany; 46 if(::read(timerfd, &howmany, sizeof howmany) != sizeof(howmany)) 47 ERR_EXIT("read"); 48 } 49 50 } 51 Timer::Timer(int val, int interval, TimerCallback cb) 52 :_timerfd(createTimer()), 53 _val(val), 54 _interval(interval), 55 _callback(std::move(cb)), 56 _isStart(false) 57 { 58 59 } 60 61 62 Timer::~Timer() 63 { 64 if(_isStart) 65 { 66 stop(); 67 ::close(_timerfd); 68 } 69 } 70 71 72 void Timer::start() 73 { 74 setTimer(_timerfd, _val, _interval); 75 _isStart = true; 76 77 struct pollfd pfd; 78 pfd.fd = _timerfd; 79 pfd.events = POLLIN; 80 81 uint64_t val; 82 int ret; 83 while(_isStart) 84 { 85 ret = ::poll(&pfd, 1, 5000); 86 if(ret == -1) 87 { 88 if(errno == EINTR) 89 continue; 90 ERR_EXIT("poll"); 91 } 92 else if(ret == 0) 93 { 94 printf("timeout\n"); 95 continue; 96 } 97 98 if(pfd.revents == POLLIN) 99 {100 readTimer(_timerfd);101 _callback();102 }103 }104 }105 106 void Timer::stop()107 {108 _isStart = false;109 stopTimer(_timerfd);110 }
View Code

 

我们可以将定时器与线程封装到一起,这样,每个线程就是一个定时器。

线程的封装如下:

1 #ifndef THREAD_H 2 #define THREAD_H 3 #include 
4 #include
5 #include
6 class Thread : boost::noncopyable 7 { 8 public: 9 10 typedef std::function
ThreadCallback;11 12 Thread(ThreadCallback cb);13 ~Thread();14 15 void start();16 void join();17 18 static void *runInThread(void *);19 20 21 private:22 23 pthread_t _threadId;24 bool _isRun;25 ThreadCallback _callback;26 };27 28 29 #endif /*THREAD_H*/
View Code
1 #include "Thread.h" 2  3 Thread::Thread(ThreadCallback cb) 4     :_threadId(0), 5      _isRun(false), 6      _callback(cb) 7 { 8  9 }10 11 Thread::~Thread()12 {13     if(_isRun)14         pthread_detach(_threadId);15 }16 17 18 void Thread::start()19 {20     pthread_create(&_threadId, NULL, runInThread, this);21     _isRun = true;22 }23 24 void Thread::join()25 {26     pthread_join(_threadId, NULL);27     _isRun = false;28 }29 30 void *Thread::runInThread(void *arg)31 {32     Thread *p = static_cast
(arg);33 p->_callback();34 return NULL;35 }
View Code

TimerThread的封装如下:

1 #ifndef TIMER_THREAD_H 2 #define TIMER_THREAD_H 3 #include 
4 #include
5 #include "Timer.h" 6 #include "Thread.h" 7 8 class TimerThread : boost::noncopyable 9 {10 public:11 typedef std::function
Callback;12 TimerThread(int val, int interval, Callback cb);13 14 void start();15 void stop();16 17 private:18 Timer _timer;19 Thread _thread;20 21 };22 23 24 #endif /*TIMER_THREAD_H*/
View Code
1 #include "TimerThread.h" 2  3 TimerThread::TimerThread(int val, int interval, Callback cb) 4     :_timer(val, interval, std::move(cb)), 5      _thread(std::bind(&Timer::start, &_timer)) 6 { 7  8 } 9 10 void TimerThread::start()11 {12     _thread.start();13 }14 15 void TimerThread::stop()16 {17     _timer.stop();18     _thread.join();19 }
View Code

测试函数如下:

1 #include "TimerThread.h" 2 #include 
3 #include
4 5 void foo() 6 { 7 printf("foo\n"); 8 } 9 10 int main(int argc, const char *argv[])11 {12 TimerThread a(3, 1, &foo);13 a.start();14 sleep(10);15 a.stop();16 return 0;17 }
View Code

在将Timer与Thread结合封装中,我们需要注意:

  a)首先,将用户要执行的任务函数bind到Timer中。

  b)然后,我们将Timer的start函数bind到Thread中。

这样,当我们开启一个该类的线程就相当于开启了一个定时器。

转载于:https://www.cnblogs.com/gjn135120/p/4023129.html

你可能感兴趣的文章
默认路由
查看>>
CYQ.Data 轻量数据层之路 框架开源系列 索引
查看>>
zabbix(2)使用自带模板完成基本监控
查看>>
安装rrdtool出现的错误
查看>>
木马隐藏地点全搜查
查看>>
来自CES 2018的5G信号:5G手机今年可能还用不上
查看>>
Subversion版本控制
查看>>
奇怪的打印纸盘故障
查看>>
hyperledger v1.0.5 区块链运维入门(一)
查看>>
Mybatis-mapper-xml-基础
查看>>
5. GC 调优(基础篇) - GC参考手册
查看>>
Windows 7 XP 模式颜色质量只有16位的解决
查看>>
SonicWall如何安全模式升级防火墙
查看>>
Linux IPC实践(3) --具名FIFO
查看>>
从Atlas到Microsoft ASP.NET AJAX(6) - Networking, Application Services
查看>>
成长之路---写好一个类
查看>>
读取 java.nio.ByteBuffer 中的字符串(String) 写入方式flash.utils.ByteArray.writeUTF
查看>>
范围管理和范围蔓延
查看>>
android90 bind方式启动服务service调用service里的方法
查看>>
前端开发薪资之各地区对比(图文分析)(share)
查看>>