使用 c++ 实现一个定时器
使用 c++ 实现一个定时器
在 Linux 应用开发中常常会用到定时器,其实定时器的实现方式有五六种,但是好多定时器的使用容易破坏 c++ 的封装,举个例子,你无法把一个类的非静态成员函数赋值给一个 struct sigaction 的成员 sa_handler 指针,如果你非要这样,只能采用静态成员函数,如果这个函数里要访问到类的多个成员变量,这些成员变量全部得改成静态成员变量,天哪,这违背了我的初心,我仅仅是想执行一个定时任务而已,却要破坏类原有得结构,所以最优雅的方式就是自己实现一个,下面我将以 timerfd 为例,实现一个毫秒级定时器类,误差 100 微妙左右。
具体实现
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
#ifndef __TIMER_H__
#define __TIMER_H__
#include <stdio.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <sys/timerfd.h>
#include <unistd.h>
#include <thread>
#include <atomic>
#include <cstdint>
#include <cstring>
#include <functional>
#include <chrono>
#include <cerrno>
class Timer {
public:
using TaskCallback = std::function<void(void)>;
Timer(uint64_t ms, const TaskCallback &callback)
: m_is_running(false)
, m_timer_fd(-1)
, m_interval_ms(ms)
, m_callback(callback) {}
~Timer() {}
void start() {
if (m_is_running) {
return;
}
m_timer_fd = timerfd_create(CLOCK_MONOTONIC, 0);
if (m_timer_fd == -1) {
perror("timerfd_create failed");
return;
}
struct itimerspec its;
memset(&its, 0, sizeof(its));
uint64_t ms = m_interval_ms;
its.it_interval.tv_sec = ms / 1000;
its.it_interval.tv_nsec = (ms % 1000) * 1000000;
its.it_value = its.it_interval;
if (timerfd_settime(m_timer_fd, 0, &its, nullptr) == -1) {
perror("timerfd_settime failed");
close(m_timer_fd);
m_timer_fd = -1;
return;
}
m_is_running = true;
m_thread = std::thread([&]() {
while (m_is_running) {
uint64_t expirations;
ssize_t bytes = read(m_timer_fd, &expirations, sizeof(expirations));
if (bytes == sizeof(expirations)) {
if (expirations > 0) {
for (uint64_t i = 0; i < expirations; ++i) {
m_callback();
}
}
} else {
if (errno == EBADF || !m_is_running) {
break;
}
perror("read timerfd failed");
}
}
});
}
void stop() {
if (!m_is_running) {
return;
}
m_is_running = false;
if (m_timer_fd != -1) {
close(m_timer_fd);
m_timer_fd = -1;
}
if (m_thread.joinable()) {
m_thread.join();
}
}
private:
int m_timer_fd;
std::atomic<bool> m_is_running;
std::thread m_thread;
uint64_t m_interval_ms;
TaskCallback m_callback;
};
#endif // __TIMER_H__
#include <iostream>
#include <signal.h>
bool is_running(true);
void handle(int sig) {
is_running = false;
}
int main() {
signal(SIGINT, handle);
auto now = std::chrono::high_resolution_clock::now();
Timer timer(1000, [&]() {
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - now).count();
std::cout << "cost: " << duration / 1000.0 << " us" << std::endl;
now = end;
});
timer.start();
while (is_running) {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
timer.stop();
return 0;
}
本文由作者按照 CC BY 4.0 进行授权