代码主要是做练习用的,水平有限,路过的大神看到代码有哪里不好的请帮忙指出来,万分感谢。
#pragma once
#include <map>
#include <mutex>
#include <deque>
#include <queue>
#include <chrono>
#include <atomic>
#include <thread>
#include <iostream>
#include <functional>
#include <condition_variable>
struct TimerNode
{
std::chrono::time_point<std::chrono::high_resolution_clock> timePoint; // 运行的时间点
std::chrono::milliseconds timePeriod; //间隔时长
int repeatNum; // 重复次数, -1表示一直重复
int id;
std::function<void()> callback;
bool operator<(const TimerNode& other) const
{
return timePoint > other.timePoint;
}
};
class Timer
{
public:
enum class IdState { Running = 0 };
Timer()
{
mbRunning.store(false);
}
~Timer()
{
mvStop();
}
void mvStart()
{
mbRunning.store(true);
moThread = std::thread([this] {this->mvLoop(); });
}
void mvStop()
{
mbRunning.store(false);
moCondVar.notify_all();
if (moThread.joinable())
{
moThread.join();
}
}
template<typename T, typename...Args>
int mvRunAfter(int ms, T&& fun, Args&&... args)
{
TimerNode node;
node.id = miTimerId.fetch_add(1);
node.repeatNum = 0;
node.timePoint = std::chrono::high_resolution_clock::now() + std::chrono::milliseconds(ms);
node.callback = std::bind(std::forward<T>(fun), std::forward<Args>(args)...);
mvAddTimeNode(node);
mapIds[node.id] = IdState::Running;
return node.id;
}
template<typename T, typename...Args>
int mvRunRepeat(int period, int repeatNum, T&& fun, Args&&... args)
{
TimerNode node;
node.id = miTimerId.fetch_add(1);
node.repeatNum = repeatNum;
node.timePeriod = std::chrono::milliseconds(period);
node.timePoint = std::chrono::high_resolution_clock::now() + node.timePeriod;
node.callback = std::bind(std::forward<T>(fun), std::forward<Args>(args)...);
mvAddTimeNode(node);
mapIds[node.id] = IdState::Running;
return node.id;
}
template<typename T, typename... Args>
int mvRunAt(const std::chrono::time_point<std::chrono::high_resolution_clock>& point, T&& fun, Args&&... args)
{
TimerNode node;
node.id = miTimerId.fetch_add(1);
node.repeatNum = 0;
node.timePoint = point;
node.callback = std::bind(std::forward<T>(fun), std::forward<Args>(args)...);
mvAddTimeNode(node);
mapIds[node.id] = IdState::Running;
return node.id;
}
template<typename T, typename... Args>
int mvRunEvery(int period, T&& fun, Args&&... args)
{
return mvRunRepeat(period, -1, fun, args...);
}
void mvClearAll()
{
std::unique_lock<std::mutex> lock(moMutex);
std::priority_queue<TimerNode> o;
mqueue.swap(o);
}
void mvCancel(int id)
{
if (mapIds.find(id) != mapIds.end())
{
mapIds.erase(id);
}
}
private:
void mvLoop()
{
while (mbRunning.load())
{
TimerNode node;
{
std::unique_lock<std::mutex> lock(moMutex);
moCondVar.wait(lock, [this] {return !mbRunning.load() || !mqueue.empty(); });
if (!mbRunning.load())
{
break;
}
node = mqueue.top();
auto diff_time = node.timePoint - std::chrono::high_resolution_clock::now();
if (std::chrono::duration_cast<std::chrono::milliseconds>(diff_time).count() > 0)
{
moCondVar.wait_for(lock, diff_time);
continue;
}
mqueue.pop();
}
node.callback();
if (node.repeatNum != 0)
{
std::unique_lock<std::mutex> lock(moMutex);
node.timePoint = std::chrono::high_resolution_clock::now() + node.timePeriod;
if (node.repeatNum > 0) node.repeatNum--;
mqueue.push(node);
}
}
}
void mvAddTimeNode(TimerNode& node)
{
std::unique_lock<std::mutex> lock(moMutex);
mqueue.push(node);
moCondVar.notify_one();
}
private:
std::priority_queue<TimerNode > mqueue;
std::mutex moMutex;
std::condition_variable moCondVar;
std::thread moThread;
std::atomic<bool> mbRunning;
std::map<int, IdState> mapIds;
std::atomic<int> miTimerId;
};
void fun1()
{
std::cout << "hello" << std::endl;
}
void fun2()
{
std::cout << "world" << std::endl;
}
void test()
{
Timer t;
t.mvStart();
t.mvRunAfter(1500, [] {std::cout << "run after" << std::endl; });
t.mvRunAt(std::chrono::high_resolution_clock::now() + std::chrono::milliseconds(3000), fun2);
t.mvRunRepeat(1000, 5, fun2);
t.mvRunEvery(1000, fun1);
std::cin.get();
std::cout << "Finished" << std::endl;
}