定时器

代码主要是做练习用的,水平有限,路过的大神看到代码有哪里不好的请帮忙指出来,万分感谢。

#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值