实现简单定时器
This commit is contained in:
@@ -2,7 +2,17 @@ cmake_minimum_required(VERSION 3.27)
|
|||||||
project(Timer)
|
project(Timer)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
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
|
main.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_link_libraries(TimerLink
|
||||||
|
Timer
|
||||||
|
)
|
||||||
|
|||||||
94
include/Timer.h
Normal file
94
include/Timer.h
Normal 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
|
||||||
18
main.cpp
18
main.cpp
@@ -1,6 +1,22 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <Timer.h>
|
||||||
|
|
||||||
int main() {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
112
src/Timer.cpp
Normal file
112
src/Timer.cpp
Normal 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
|
||||||
Reference in New Issue
Block a user