实现最小堆的定时器

#ifndef TIMER_HPP_
#define TIMER_HPP_

#include <memory>
#include <queue>
#include <thread>
#include <functional>
#include <string>
#include <unordered_map>
#include <mutex>
#include <condition_variable>

#include "rclcpp/rclcpp.hpp"

#define WORK_MODE 1
#define WORK_PLAN ((WORK_MODE << 2) + 1)
#define CLEAR_PLAN ((WORK_MODE << 2) + 2)

using callbackPtr = std::function<void()>;

struct MinHeapNode
{
    std::string time;
    callbackPtr function;
    int id;

    MinHeapNode() : time(""), function(nullptr), id(0) {};
    MinHeapNode(const std::string &time,const callbackPtr &f,const int &id) 
    : time(time), function(f), id(id) {};

    bool operator<(const MinHeapNode &n) const {
        return time > n.time;
    }

    bool comp(const MinHeapNode& a, const MinHeapNode &b) {
        return a.time > b.time;
    }

    bool operator==(const MinHeapNode &n) const
    {
        if(id == n.id && time == n.time)
            return true;
        else
            return false;
    }
};

class MinHeap : public std::priority_queue<MinHeapNode>
{
public:
    bool addnode(MinHeapNode node);
    bool rmvnode(MinHeapNode node);
    void clear();
};

class TIME
{
public:
    TIME();
    ~TIME();
    void addTimer(std::string time, callbackPtr callbackfunctino, int id);
    void rmvTimer(std::string time, int id);
    void start();
    void stop();
    void run_tick();
    void run_callback();
    static std::shared_ptr<TIME> getInstance(void);
    

private:
    std::shared_ptr<MinHeap> _minheap;
    std::shared_ptr<std::deque<callbackPtr>> _callback;
    std::thread *_tickThread;
    std::thread *_callbackThread;
    std::mutex _tick_mutex;
    std::mutex _callback_mutex;
    std::condition_variable _cv;
};

#endif
#include "timer.hpp"
#include <algorithm>
#include <cstring>
#include <string>


bool MinHeap::addnode(MinHeapNode node)
{
    push(node);
    return true;
}

bool MinHeap::rmvnode(MinHeapNode node)
{
    auto it = std::find(this->c.begin(), this->c.end(), node);
    if (it == this->c.end()) {
        return false;
    }
    if (it == this->c.begin()) {
        this->pop();
    } else {
        this->c.erase(it);
        std::make_heap(this->c.begin(), this->c.end(), this->comp);
    }
    return true;
}

void MinHeap::clear()
{
    while(!this->empty()) {
        this->pop();
    }
}

TIME::TIME()
{
    _minheap = std::make_shared<MinHeap>();
    _callback = std::make_shared<std::deque<callbackPtr>>();
    _tickThread = nullptr;
    _callbackThread = nullptr;
}

TIME::~TIME()
{
    if (_tickThread) {
        if (_tickThread->joinable())
            _tickThread->join();
        delete _tickThread;
        _tickThread = nullptr;
    }
    
    if (_callbackThread) {
        if (_callbackThread->joinable())
            _callbackThread->join();
        delete _callbackThread;
        _callbackThread = nullptr;
    }
}

void TIME::addTimer(std::string time, callbackPtr callbackfunctino, int id)
{
    MinHeapNode node(time, callbackfunctino, id);
    std::unique_lock<std::mutex> mut(_tick_mutex);
    _minheap->addnode(node);
    RCLCPP_INFO(rclcpp::get_logger("time"), "ADD TIMER %s %d!", time.c_str(), id);
}

void TIME::rmvTimer(std::string time, int id)
{
    MinHeapNode node(time, nullptr, id);
    std::unique_lock<std::mutex> mut(_tick_mutex);
    _minheap->rmvnode(node);
    RCLCPP_INFO(rclcpp::get_logger("time"), "RMV TIMER %s %d!", time.c_str(), id);
}

void TIME::start()
{
    RCLCPP_INFO(rclcpp::get_logger("time"), "TIMER START");
    _tickThread = new std::thread(std::bind(&TIME::run_tick, this));
    _callbackThread = new std::thread(std::bind(&TIME::run_callback, this));
    _tickThread->detach();
    _callbackThread->detach();
}

void TIME::stop()
{
    RCLCPP_INFO(rclcpp::get_logger("time"), "TIMER STOP");
    _minheap->clear();
    _callback->clear();
    if (_tickThread->joinable())
        _tickThread->join();
    if (_callbackThread->joinable())
        _callbackThread->join();
    delete _tickThread;
    delete _callbackThread;
    _tickThread = nullptr;
    _callbackThread = nullptr;
}

std::shared_ptr<TIME> TIME::getInstance(void)
{
    static std::shared_ptr<TIME> instance = nullptr;
    if (!instance) {
        instance = std::make_shared<TIME>();
    }
    return instance;
}

int cmpdate(std::string date) 
{
    time_t now = time(nullptr);
    struct tm timeinfo;
    if (!strptime(date.c_str(), "%Y.%m.%d %H:%M:%S",  &timeinfo)) {
        RCLCPP_ERROR(rclcpp::get_logger("time"), "FORMAT ERROR!");
    }
    time_t timeStamp = mktime(&timeinfo);
    std::cout << date << " " <<timeStamp  << "-" << now << "=" << timeStamp - now << std::endl;
 
    return timeStamp - now;
}

void TIME::run_tick()
{
    RCLCPP_INFO(rclcpp::get_logger("time"), "RUN TICK");
    while (true)
    {
        std::cout<< "tick!" << std::endl;
        std::unique_lock<std::mutex> mut(_tick_mutex);
        if (_minheap->empty()) {
            return;
        }
        MinHeapNode node = _minheap->top();
        int cmptime = cmpdate(node.time);
        if (cmptime > 0) {
            RCLCPP_INFO(rclcpp::get_logger("time"), "steal wait!");
        } else if (cmptime >= -60) {
            RCLCPP_INFO(rclcpp::get_logger("time"), "time out!");
            _minheap->pop();
            std::unique_lock<std::mutex> fmut(_callback_mutex);
            _callback->push_back(node.function);
            _cv.notify_one();
            fmut.unlock();
        } else {
            _minheap->pop();
            RCLCPP_ERROR(rclcpp::get_logger("time"), "run time low than now time!");
        }
        mut.unlock();
        std::this_thread::sleep_for(std::chrono::seconds(30));
    }
}

void TIME::run_callback()
{
    RCLCPP_INFO(rclcpp::get_logger("time"), "RUN CALLBACK");
    while (true)
    {
        std::unique_lock<std::mutex> mut(_callback_mutex);
        _cv.wait(mut, [this]() {return !_callback->empty();});
        callbackPtr cp = _callback->front();
        if (!cp) {
            RCLCPP_ERROR(rclcpp::get_logger("time"), "callback function is empty!");
            return;
        }
        _callback->pop_front();
        cp();
        RCLCPP_INFO(rclcpp::get_logger("time"), "exec!");
        mut.unlock();
        std::this_thread::yield();
    }
}
int main(){
    
    std::shared_ptr<TIME>  timerMgr = TIME::getInstance();

    timerMgr->addTimer(next.starttime, std::bind(&Schedule::start_action, this), WORK_PLAN);
    timerMgr->addTimer(next.endtime, std::bind(&Schedule::stop_action, this), WORK_PLAN);

    timerMgr->start();

    for (auto s : schedule_list_) {
        timerMgr->rmvTimer(s, WORK_PLAN);
    }
}

根据执行时间插入定时器中,定时器维护两个线程,一个线程判断超时时间,一个线程执行回调函数。

定时器插入删除根据最小堆,时间前的任务插入到前面,删除根据时间和定时器类型定点删除。

定时器支持同一时刻多类型任务插入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值