c++定时器

定时器作为常用的组件,通常的实现方式有几种:链表,最小堆,时间轮,等等。

1 链表

性能比较弱,适用于简单的场景,查询、插入、删除效率都不高

2 最小堆

性能比较高,适用于定时器需求较多的场景

3 时间轮

性能比较高,适用于定时器需求很大的场景

 

    在网上查了一些资料,真正可以直接用的代码并不多,不可以直接运行,就不能给读者以更加感性的认识,也就不愿意更多的去分析代码和学习。所以,以 https://www.cnblogs.com/junye/p/5836552.html 为例,将它的最小堆实现,做了一些修改,可以接在gcc 4.8.2以上的环境编译通过并运行。将代码保存为 a.cc,编译命令为

g++ -g -o a a.cc -std=c++11

具体的代码如下:

#include <iostream>
#include <chrono>
#include <thread>
#include <vector>
#include <sys/time.h>

// global declaration
typedef void (*Fun)(void);

class Timer;
class TimerManager;

// header file for Timer
class Timer
{
public:
    enum TimerType { ONCE, CIRCLE };

    Timer(TimerManager& manager);
    ~Timer();

    void Start(Fun fun, unsigned interval, TimerType timeType = CIRCLE);
    void Stop();

private:
    void OnTimer(unsigned long long now);

private:
    friend class TimerManager;
    TimerManager& manager_;
    TimerType timerType_;
    Fun timerFun_;
    unsigned interval_;
    unsigned long long expires_;

    int heapIndex_;
};

// header file for TimerManager
class TimerManager
{
public:
    static unsigned long long GetCurrentMillisecs();
    void DetectTimers();

private:
    friend class Timer;
    void AddTimer(Timer* timer);
    void RemoveTimer(Timer* timer);

    void UpHeap(int index);
    void DownHeap(int index);
    void SwapHeap(int, int index2);

private:
    struct HeapEntry
    {
        unsigned long long time;
        Timer* timer;
    };
    std::vector<HeapEntry> heap_;
};

// implemetation of Timer

Timer::Timer(TimerManager& manager)
    : manager_(manager)
    , heapIndex_(-1)
{
    // to-do
}

Timer::~Timer()
{
    Stop();
}

inline void Timer::Start(Fun fun, unsigned interval, TimerType timeType)
{
    Stop();
    interval_ = interval;
    timerFun_ = fun;
    timerType_ = timeType;
    this->expires_ = this->interval_ + TimerManager::GetCurrentMillisecs();
    manager_.AddTimer(this);
}

void Timer::Stop()
{
    if (heapIndex_ != -1)
    {
        manager_.RemoveTimer(this);
        heapIndex_ = -1;
    }
}

void Timer::OnTimer(unsigned long long now)
{
    if (timerType_ == Timer::CIRCLE)
    {
        expires_ = interval_ + now;
        manager_.AddTimer(this);
    }
    else
    {
        heapIndex_ = -1;
    }
    timerFun_();
}

// implemetation of TimerManager

void TimerManager::AddTimer(Timer* timer)
{
    timer->heapIndex_ = heap_.size();
    HeapEntry entry = { timer->expires_, timer };
    heap_.push_back(entry);
    UpHeap(heap_.size() - 1);
}

void TimerManager::RemoveTimer(Timer* timer)
{
    int index = timer->heapIndex_;
    if (!heap_.empty() && index < heap_.size())
    {
        if (index == heap_.size() - 1)
        {
            heap_.pop_back();
        }
        else
        {
            SwapHeap(index, heap_.size() - 1);
            heap_.pop_back();
            int parent = (index - 1) / 2;
            if (index > 0 && heap_[index].time < heap_[parent].time)
            {
                UpHeap(index);
            }
            else
            {
                DownHeap(index);
            }
        }
    }
}

void TimerManager::DetectTimers()
{
    unsigned long long now = GetCurrentMillisecs();

    while (!heap_.empty() && heap_[0].time <= now)
    {
        Timer* timer = heap_[0].timer;
        RemoveTimer(timer);
        timer->OnTimer(now);
    }
}

void TimerManager::UpHeap(int index)
{
    int parent = index >> 1;
    while (index > 0 && heap_[index].time < heap_[parent].time)
    {
        SwapHeap(index, parent);
        index = parent;
        parent = index >> 1;
    }
}

void TimerManager::DownHeap(int index)
{
    int child = (index << 1) + 1;
    while (child < heap_.size())
    {
        int minChild = (child + 1 == heap_.size() || heap_[child].time < heap_[child + 1].time)? child : child + 1;
        if (heap_[index].time < heap_[minChild].time)
            break;
        SwapHeap(index, minChild);
        index = minChild;
        child = (index << 1) + 1;
    }
}

void TimerManager::SwapHeap(int index1, int index2)
{
    HeapEntry tmp = heap_[index1];
    heap_[index1] = heap_[index2];
    heap_[index2] = tmp;
    heap_[index1].timer->heapIndex_ = index1;
    heap_[index2].timer->heapIndex_ = index2;
}

unsigned long long TimerManager::GetCurrentMillisecs()
{
    timeval tv;
    ::gettimeofday(&tv, 0);
    unsigned long long ret = tv.tv_sec;
    return ret * 1000 + tv.tv_usec / 1000;
}

// test code

void TimerHandler_1()
{
    std::cout << "TimerHandler_1" << std::endl;
}

void TimerHandler_2()
{
    std::cout << "TimerHandler_2" << std::endl;
}

void TimerHandler_3()
{
    std::cout << "TimerHandler_3" << std::endl;
}

void TimerHandler_4()
{
    std::cout << "TimerHandler_4" << std::endl;
}

int main()
{
    TimerManager tm;

    Timer t1(tm);
    t1.Start(&TimerHandler_1, 1000);

    Timer t2(tm);
    t2.Start(&TimerHandler_2, 500);

    Timer t3(tm);
    t3.Start(&TimerHandler_3, 1500);

    Timer t4(tm);
    t4.Start(&TimerHandler_4, 100);

    while (true)
    {
        tm.DetectTimers();
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    return 0;
}

  

 

posted @ 2019-03-14 10:33  warnet  阅读(6020)  评论(0编辑  收藏  举报