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;
}

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM