#ifndef TIMER_H
#define TIMER_H
#include <functional>
#include <thread>
#include <atomic>
#include <chrono>
#include <mutex>
#include <condition_variable>
#include <type_traits>
#include <utility>
namespace tutils {
class Timer {
public:
enum Mode {
OneShot,
Repeating
};
// 成员函数
template <typename ClassType, typename... Args>
Timer(ClassType* obj, void (ClassType::*method)(Args...), Args... args)
: callback([=] { (obj->*method)(args...); })
{
static_assert(std::is_member_function_pointer<decltype(method)>::value,
"Must be a member function pointer");
}
// 普通函数
template <typename Callable, typename... Args>
Timer(Callable&& func, Args&&... args)
: callback([func = std::forward<Callable>(func),
args = std::make_tuple(std::forward<Args>(args)...), this] {apply_impl(func, args);})
{
}
~Timer() {
stop();
}
void setSingleShot(bool singleShot) {
mode = singleShot ? OneShot : Repeating;
}
void start(int timeout_ms) {
std::unique_lock<std::mutex> lock(mutex);
this->timeout = timeout_ms;
// 计算下次回调时间(当前时间+超时时间)
callback_time = std::chrono::steady_clock::now() +
std::chrono::milliseconds(timeout_ms);
if (!running) {
running = true;
// 确保之前的线程已完全停止,解决跨线程调用崩溃问题
if (worker.joinable()) {
lock.unlock();
worker.join();
lock.lock();
}
lock.unlock(); // 解锁后再创建线程
worker = std::thread([this] {
std::unique_lock<std::mutex> lock(mutex);
while (running) {
// 计算需要等待的时间
auto now = std::chrono::steady_clock::now();
auto wait_duration = callback_time - now;
// 超时或刚好到期
if (wait_duration <= wait_duration.zero()) {
if (callback) {
lock.unlock();
callback(); // 执行回调时不持有锁
lock.lock();
}
if (mode == OneShot) {
running = false;
break; // 单次模式退出循环
} else {
// 重复模式重新计算下次时间
callback_time = std::chrono::steady_clock::now() +
std::chrono::milliseconds(timeout);
continue;
}
}
// 等待直到超时或被唤醒
if (cv.wait_for(lock, wait_duration, [this] { return !running; })) {
break; // 被stop唤醒
}
// 被start重新设置时间唤醒
if (running && callback) {
lock.unlock();
callback();
lock.lock();
if (mode == OneShot) {
running = false;
break;
} else {
callback_time = std::chrono::steady_clock::now() +
std::chrono::milliseconds(timeout);
}
}
}
});
} else {
// 已经在运行,通知线程重新计算等待时间
cv.notify_all();
}
}
void stop() {
std::unique_lock<std::mutex> lock(mutex);
if (running) {
running = false;
cv.notify_all(); // 唤醒等待的线程
lock.unlock(); // 解锁后再join
if (worker.joinable()) {
worker.join();
}
}
}
private:
template <typename F, typename Tuple, size_t... I>
void apply_impl(F&& f, Tuple&& t, std::index_sequence<I...>) {
f(std::get<I>(std::forward<Tuple>(t))...);
}
template <typename F, typename Tuple>
void apply_impl(F&& f, Tuple&& t) {
apply_impl(std::forward<F>(f),
std::forward<Tuple>(t),
std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>{});
}
std::function<void()> callback;
std::thread worker;
std::atomic<bool> running{false};
std::chrono::steady_clock::time_point callback_time;
int timeout = 0;
Mode mode = OneShot;
std::mutex mutex;
std::condition_variable cv;
};
} // namespace tutils
#endif // TIMER_H
C++实现一个定时器类
于 2025-07-02 11:29:39 首次发布