C++实现一个定时器类

#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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值