定时器要求在固定的时间异步执行一个操作,比如boost库中的boost::asio::deadline_timer,以及MFC中的定时器。也可以利用c++11的thread, mutex, condition_variable 来实现一个定时器。
1、使用C++11中的thread, mutex, condition_variable来实现一个定时器。
注:此算法会每一个任务创建一个线程,不推荐。推荐用最下面第2种时间轮算法
#include
#include
#include
#include
#include
class Timer {
public:
Timer() :_expired(true), _try_to_expire(false) {}
Timer(const Timer& t) {
_expired = t._expired.load();
_try_to_expire = t._try_to_expire.load();
}
~Timer() {
Expire();
}
void StartTimer(int interval, std::function<void()> task) {
if (_expired == false) {
return;
}
_expired = false;
std::thread([this, interval, task]() {
while (!_try_to_expire) {
std::this_thread::sleep_for(std::chrono::milliseconds(interval));
task();
}
{
std::lock_guard<std::mutex> locker(_mutex);
_expired = true;
_expired_cond.notify_one();
}
}).detach();
}
void Expire() {
if (_expired) {
return;
}
if (_try_to_expire) {
return;
}
_try_to_expire = true;
{
std::unique_lock<std::mutex> locker(_mutex);
_expired_cond.wait(locker, [this] {return _expired == true; });
if (_expired == true) {
_try_to_expire = false;
}
}
}
private:
std::atomic<bool> _expired;
std::atomic<bool> _try_to_expire;
std::mutex _mutex;
std::condition_variable _expired_cond;
};
int main() {
Timer t;
t.StartTimer(1000, []() {std::cout << "Hello World!" << std::endl; });
std::this_thread::sleep_for(std::chrono::seconds(4));
t.Expire();
return 0;
}
2、使用时间轮算法:Linux内核就有这个算法。这里也有一个用户态的实现供参考:github.com/facebook/folly。它的高精度版本能实现微妙级别的定时。下面是一个简单的时间轮定时器的C++实现。原文的代码有问题,不能循环定时,经修改已经支持:
#include
#include
#include
#include
#include
#include
class TimerWheel {
public:
using Task = std::function<void()>;
explicit TimerWheel(size_t wheel_size, int interval_ms)
: wheel_size_(wheel_size),
interval_ms_(interval_ms),
wheel_(wheel_size),
current_index_(0) {}
~TimerWheel() {
Stop();
}
void Start() {
if (running_) {
return;
}
running_ = true;
thread_ = std::thread([this]() {
while (running_) {
std::this_thread::sleep_for(std::chrono::milliseconds(interval_ms_));
Tick();
}
std::cout << "timer oooops!" << std::endl;
});
thread_.detach();
}
void Stop() {
if (!running_) {
return;
}
running_ = false;
if (thread_.joinable()) {
thread_.join();
}
}
void AddTask(int timeout_ms, Task task) {
std::lock_guard<std::mutex> lock(mutex_);
size_t ticks = timeout_ms / interval_ms_;
size_t index = (current_index_ + ticks) % wheel_size_;
size_t allindex = index;
for (size_t i = 1 ; allindex < wheel_size_; i++)
{
allindex = index * i;
if (allindex >= wheel_size_)
break;
wheel_[allindex].push_back(task);
}
}
private:
void Tick() {
std::lock_guard<std::mutex> lock(mutex_);
auto& tasks = wheel_[current_index_];
for (const auto& task : tasks) {
task();
}
//tasks.clear();
current_index_ = (current_index_ + 1) % wheel_size_;
}
private:
size_t wheel_size_;
int interval_ms_;
std::vector<std::list<Task>> wheel_;
size_t current_index_;
bool running_ = false;
std::thread thread_;
std::mutex mutex_;
};
使用方法:
使用static声明以免被析构,可在cpp类外全局声明,第一个参数为任务容器最大数量,第二个参数为定时判断的毫秒数即最低检测时间单位
static TimerWheel timer(10, 1000);
在要使用的地方,启动并添加任务
timer.Start();
timer.AddTask(2000, []() {std::cout << "Task 1" << std::endl; });
timer.AddTask(3000, []() {std::cout << "Task 2" << std::endl; });
可以在需要的时候停止
timer.Stop();
原文链接:https://blog.csdn.net/sinat_28305511/article/details/131495316