实现简单定时器

This commit is contained in:
2024-01-23 16:27:37 +08:00
parent 5097161b53
commit ca23184273
4 changed files with 234 additions and 2 deletions

View File

@@ -2,7 +2,17 @@ cmake_minimum_required(VERSION 3.27)
project(Timer)
set(CMAKE_CXX_STANDARD 17)
include_directories(include)
add_executable(Timer
add_library(Timer
src/Timer.cpp
include/Timer.h
)
add_executable(TimerLink
main.cpp
)
target_link_libraries(TimerLink
Timer
)

94
include/Timer.h Normal file
View File

@@ -0,0 +1,94 @@
//
// Created by ling on 24-1-23.
//
#ifndef TIMER_TIMER_H
#define TIMER_TIMER_H
#include <ctime>
#include <functional>
#include <mutex>
#include <list>
#include <thread>
#include <atomic>
#include <condition_variable>
#include <future>
namespace ling {
/// 低精度定时器,最大时间粒度为秒
class Timer {
private:
struct Task {
std::time_t time;
int64_t interval;
std::function<void()> fun;
int64_t id;
void operator()();
};
//执行函数,可以用来结合线程池使用
static std::function<void(std::function<void()> fun)> call;
static int64_t nextId;
static std::mutex mutex;
static std::list<Task> list;
static std::thread thread;
static std::atomic<bool> flag;
static std::condition_variable listCV;
std::function<void()> recall;
int64_t id = 0;
Task task;
protected:
static void addTask(const Task &task);
public:
template<typename F, typename... Args>
explicit Timer(F &&f, Args &&...args) {
this->id = nextId++;
std::function<decltype(f(args...))()> func = std::bind(std::forward<F>(f), std::forward<Args>(
args)...); // 连接函数和参数定义,特殊函数类型,避免左右值错误
auto task_ptr = std::make_shared<std::packaged_task<decltype(f(args...))()>>(func);
std::function<void()> warpper_func = [task_ptr, this]() {
(*task_ptr)();
this->recall();
};
this->recall = [this, func]() {
auto task_ptr = std::make_shared<std::packaged_task<decltype(f(args...))()>>(func);
std::function<void()> warpper_func = [task_ptr, this]() {
(*task_ptr)();
this->recall();
};
this->task.time = std::time(nullptr) + this->task.interval;
this->task.fun = warpper_func;
addTask(task);
};
task.fun = warpper_func;
task.id = this->id;
}
/// 启动定时器
void start(int64_t interval);
/// 重新启动定时器
void start();
void stop() const;
/// 设置任务执行器
static void setCall(const std::function<void(std::function<void()>)> &call);
/// 立即停止定时器,没有执行的任务将全部丢弃
static void stopAll();
virtual ~Timer();
};
} // ling
#endif //TIMER_TIMER_H

View File

@@ -1,6 +1,22 @@
#include <iostream>
#include <Timer.h>
int main() {
std::cout << "Hello, World!" << std::endl;
{
ling::Timer timer([]() {
std::cout << "Hello World" << std::endl;
});
timer.start(5);
getchar();
std::cout << "停止" << std::endl;
timer.stop();
getchar();
std::cout << "重新启动" << std::endl;
timer.start();
getchar();
}
std::cout << "释放" << std::endl;
getchar();
ling::Timer::stopAll();
return 0;
}

112
src/Timer.cpp Normal file
View File

@@ -0,0 +1,112 @@
//
// Created by ling on 24-1-23.
//
#include "Timer.h"
#include <thread>
#include <csignal>
namespace ling {
std::function<void(std::function<void()> fun)> Timer::call = [](const std::function<void()> &fun) {
std::thread thread1([fun]() {
fun();
});
thread1.detach();
};
int64_t Timer::nextId = 1;
std::mutex Timer::mutex;
std::list<Timer::Task> Timer::list;
std::condition_variable Timer::listCV;
std::atomic<bool> Timer::flag{true};
std::thread Timer::thread([]() {
while (flag.load()) {
{
std::unique_lock<std::mutex> lock(mutex);
// 如果任务列表为空,阻塞当前线程
if (list.empty()) {
listCV.wait(lock);
}
if (list.empty())
continue;
Task task = list.front();
std::time_t time = std::time(nullptr);
if (task.time <= time) {
call(task.fun);
list.pop_front();
continue;
}
}
sleep(1);
}
});
void Timer::Task::operator()() {
}
void Timer::setCall(const std::function<void(std::function<void()>)> &fun) {
ling::Timer::call = fun;
}
void Timer::addTask(const Timer::Task &task) {
{
std::unique_lock<std::mutex> lock(mutex);
// 后添加的定时任务触发时间一般都比先添加的任务晚,所以从后向前遍历列表,节省一些时间
for (auto it = list.rbegin(); it != list.rend(); ++it) {
if (it->time > task.time) {
list.insert(it.base(), task);
goto back;
}
}
list.push_back(task);
}
back:
listCV.notify_one();
}
void Timer::stopAll() {
{
std::unique_lock<std::mutex> lock(mutex);
flag.store(false);
list.clear();
listCV.notify_all();
}
thread.join();
}
void Timer::start(int64_t interval) {
{
std::unique_lock<std::mutex> lock(mutex);
for (auto it = list.begin(); it != list.end(); ++it) {
if (it->id == this->id) {
list.erase(it);
break;
}
}
}
this->task.time = std::time(nullptr) + interval;
this->task.interval = interval;
addTask(task);
}
void Timer::stop() const {
std::unique_lock<std::mutex> lock(mutex);
for (auto it = list.begin(); it != list.end(); ++it) {
if (it->id == this->id) {
list.erase(it);
break;
}
}
}
void Timer::start() {
start(this->task.interval);
}
Timer::~Timer() {
stop();
}
} // ling