赞
踩
定时器要求在固定的时间异步执行一个操作,比如boost库中的boost::asio::deadline_timer,以及MFC中的定时器。也可以利用c++11的thread, mutex, condition_variable 来实现一个定时器。
1、使用C++11中的thread, mutex, condition_variable来实现一个定时器。
注:此算法会每一个任务创建一个线程,不推荐。推荐用最下面第2种时间轮算法
#include <iostream> #include <chrono> #include <thread> #include <mutex> #include <condition_variable> 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 <chrono> #include <functional> #include <list> #include <mutex> #include <thread> #include <vector> 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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。