0.前言
C++学习笔记。
该学习笔记练习使用了 std::function 函数对象,std::bind 函数适配器,std::priority_queue 创建最大堆,std::mutex 创建互斥锁,std::condition_variable 条件变量。
1.正文
C++实现一个简单的定时器任务,可以添加定时器。
cpp
#include <iostream>
#include <string>
#include <chrono>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <queue>
#include <thread>
#include <functional>
#include <cstdint>
using SteadyClock = std::chrono::steady_clock;
using TimePoint = std::chrono::steady_clock::time_point;
using MillionSecond = std::chrono::milliseconds;
class TimerTask {
public:
using TimerFunc = std::function<void(const TimerTask & timer)>;
enum {
TIMER_TASK_PERIOD,
TIMER_TASK_ONESHOT,
};
uint32_t id_;
int type_;
MillionSecond interval_;
TimePoint trigger_point_;
TimerFunc func_;
};
class TimerCompare {
public:
bool operator()(const TimerTask &a, const TimerTask &b) {
return a.trigger_point_ > b.trigger_point_;
}
};
class TimerTaskThread {
public:
int add(bool oneshot, int interval_ms, const TimerTask::TimerFunc &func)
{
TimerTask timer;
timer.type_ = oneshot ? TimerTask::TIMER_TASK_ONESHOT : TimerTask::TIMER_TASK_PERIOD;
timer.interval_ = MillionSecond(interval_ms);
timer.trigger_point_ = SteadyClock::now() + timer.interval_;
timer.func_ = func;
{
std::unique_lock<std::mutex> lock;
timer.id_ = id_pool_++;
timer_queue_.push(timer);
cv_notify_.notify_one();
}
return timer.id_ ;
}
int remove(int id) {
std::unique_lock<std::mutex> lock;
std::vector<TimerTask> temp;
while(!timer_queue_.empty()) {
auto timer = timer_queue_.top();
timer_queue_.pop();
if(timer.id_ == id) {
continue;
}
temp.push_back(timer);
}
for(auto timer : temp) {
timer_queue_.push(timer);
}
cv_notify_.notify_one();
return 0;
}
TimePoint top(void) {
if(timer_queue_.empty()) {
return TimePoint::max();
}
return timer_queue_.top().trigger_point_;
}
TimePoint now(void) {
return SteadyClock::now();
}
void start(void) {
running_ = true;
// std::thread([this](){
// run();
// }).detach();
std::thread(&TimerTaskThread::run, this).detach();
}
void process_timer(TimerTask &timer) {
timer.func_(timer);
if(timer.type_ == TimerTask::TIMER_TASK_PERIOD) {
timer.trigger_point_ = SteadyClock::now() + timer.interval_;
timer_queue_.push(timer);
}
}
void run(void) {
while(running_) {
std::unique_lock<std::mutex> lock(mutex_);
cv_notify_.wait_until(lock, top());
while(!timer_queue_.empty() && now() >= top()) {
if(!running_)
break;
auto timer = timer_queue_.top();
timer_queue_.pop();
process_timer(timer);
}
}
}
void dump()
{
std::cout << "timertaskthread dump" << std::endl;
}
private:
using PriorityQueue = std::priority_queue<TimerTask, std::vector<TimerTask>, TimerCompare>;
PriorityQueue timer_queue_;
int running_;
std::mutex mutex_;
std::condition_variable cv_notify_;
uint32_t id_pool_;
};
int main(int argc, char *argv[]) {
TimerTaskThread timer_task;
timer_task.start();
std::cout << std::chrono::steady_clock::now().time_since_epoch().count() << std::endl;
timer_task.add(false, 2000, [](const TimerTask & timer) {
std::cout << std::chrono::steady_clock::now().time_since_epoch().count() << std::endl;
std::cout << "timer task 1" << std::endl;
});
timer_task.add(false, 2000, [](const TimerTask & timer) {
std::cout << std::chrono::steady_clock::now().time_since_epoch().count() << std::endl;
std::cout << "timer task 1" << std::endl;
});
timer_task.add(false, 4000, [](const TimerTask & timer) {
std::cout << std::chrono::steady_clock::now().time_since_epoch().count() << std::endl;
std::cout << "timer task 2" << std::endl;
});
auto fun1 = std::bind(&TimerTaskThread::dump, &timer_task);
int timer_id_1 = timer_task.add(false, 200, fun1);
int count = 0;
while(1) {
std::this_thread::sleep_for(std::chrono::seconds(1));
count++;
if(count == 2) {
timer_task.remove(timer_id_1);
}
}
return 0;
}
执行结果
