KBEngine中的定时器

在BaseApp CellApp等众多的App中都继承了handleTimeout接口,现在决定把它单独拿出来看一下,有空再慢慢注释,或者写一个简版的Timer


class TimerHandle
{
public:
    explicit TimerHandle(TimeBase * pTime = NULL) : pTime_( pTime ) {}

    void cancel();
    void clearWithoutCancel()   { pTime_ = NULL; }

    bool isSet() const      { return pTime_ != NULL; }

    friend bool operator==( TimerHandle h1, TimerHandle h2 );
    TimeBase * time() const { return pTime_; }

private:
    TimeBase * pTime_;
};

inline bool operator==( TimerHandle h1, TimerHandle h2 )
{
    return h1.pTime_ == h2.pTime_;
}


/**
 *  必须继承这个接口
 *  来接收timer->handleTimeout事件
 */
class TimerHandler
{
public:
    TimerHandler() : numTimesRegistered_( 0 ) {}
    virtual ~TimerHandler()
    {
        KBE_ASSERT( numTimesRegistered_ == 0 );
    };

    virtual void handleTimeout(TimerHandle handle, void * pUser) = 0;

protected:
    virtual void onRelease( TimerHandle handle, void * pUser ) {
    }

private:
    friend class TimeBase;

    void incTimerRegisterCount() { ++numTimesRegistered_; }
    void decTimerRegisterCount() { --numTimesRegistered_; }

    void release( TimerHandle handle, void * pUser )
    {
        this->decTimerRegisterCount();
        this->onRelease( handle, pUser );
    }

    int numTimesRegistered_;
};

class TimeBase
{
public:
    TimeBase(TimersBase &owner, TimerHandler* pHandler, 
        void* pUserData);
    
    virtual ~TimeBase(){}

    void cancel();

    void * getUserData() const  { return pUserData_; }

    bool isCancelled() const{ return state_ == TIME_CANCELLED; }
    bool isExecuting() const{ return state_ == TIME_EXECUTING; }

protected:
    enum TimeState
    {
        TIME_PENDING,
        TIME_EXECUTING,
        TIME_CANCELLED
    };

    TimersBase& owner_;
    TimerHandler * pHandler_;
    void *pUserData_;
    TimeState state_;
};

class TimersBase
{
public:
    virtual void onCancel() = 0;
};

template<class TIME_STAMP>
class TimersT : public TimersBase
{
public:
    typedef TIME_STAMP TimeStamp;

    TimersT();
    virtual ~TimersT();
    
    inline uint32 size() const  { return timeQueue_.size(); }
    inline bool empty() const   { return timeQueue_.empty(); }
    
    int process(TimeStamp now);
    bool legal( TimerHandle handle ) const;
    TIME_STAMP nextExp( TimeStamp now ) const;
    void clear( bool shouldCallCancel = true );
    
    bool getTimerInfo( TimerHandle handle, 
                    TimeStamp& time, 
                    TimeStamp&  interval,
                    void *& pUser ) const;
    
    TimerHandle add(TimeStamp startTime, TimeStamp interval,
                        TimerHandler* pHandler, void * pUser);
    
private:
    
    typedef std::vector<KBEngine::TimeBase *> Container;
    Container container_;

    void purgeCancelledTimes();
    void onCancel();

    class Time : public TimeBase
    {
    public:
        Time( TimersBase & owner, TimeStamp startTime, TimeStamp interval,
            TimerHandler * pHandler, void * pUser );

        TIME_STAMP time() const         { return time_; }
        TIME_STAMP interval() const     { return interval_; }

        void triggerTimer();

    private:
        TimeStamp           time_;
        TimeStamp           interval_;

        Time( const Time & );
        Time & operator=( const Time & );
    };

    class Comparator
    {
    public:
        bool operator()(const Time* a, const Time* b)
        {
            return a->time() > b->time();
        }
    };
    
    class PriorityQueue
    {
    public:
        typedef std::vector<Time *> Container;

        typedef typename Container::value_type value_type;
        typedef typename Container::size_type size_type;

        bool empty() const              { return container_.empty(); }
        size_type size() const          { return container_.size(); }

        const value_type & top() const  { return container_.front(); }

        void push( const value_type & x )
        {
            container_.push_back( x );
            std::push_heap( container_.begin(), container_.end(),
                    Comparator() );
        }

        void pop()
        {
            std::pop_heap( container_.begin(), container_.end(), Comparator() );
            container_.pop_back();
        }

        Time * unsafePopBack()
        {
            Time * pTime = container_.back();
            container_.pop_back();
            return pTime;
        }

        Container & container()     { return container_; }

        void make_heap()
        {
            std::make_heap( container_.begin(), container_.end(),
                    Comparator() );
        }

    private:
        Container container_;
    };
    
    PriorityQueue   timeQueue_;
    Time *          pProcessingNode_;
    TimeStamp       lastProcessTime_;
    int             numCancelled_;

    TimersT( const TimersT & );
    TimersT & operator=( const TimersT & );

};

typedef TimersT<uint32> Timers;
typedef TimersT<uint64> Timers64;
}

template<class TIME_STAMP>
TimersT<TIME_STAMP>::TimersT():
    timeQueue_(),
    pProcessingNode_( NULL ),
    lastProcessTime_( 0 ),
    numCancelled_( 0 )
{
}

template<class TIME_STAMP>
TimersT<TIME_STAMP>::~TimersT()
{
    this->clear();
}

template <class TIME_STAMP>
TimerHandle TimersT< TIME_STAMP >::add( TimeStamp startTime,
        TimeStamp interval, TimerHandler * pHandler, void * pUser )
{
    Time * pTime = new Time( *this, startTime, interval, pHandler, pUser );
    timeQueue_.push( pTime );
    return TimerHandle( pTime );
}

template <class TIME_STAMP>
void TimersT< TIME_STAMP >::onCancel()
{
    ++numCancelled_;

    // If there are too many cancelled timers in the queue (more than half),
    // these are flushed from the queue immediately.

    if (numCancelled_ * 2 > int(timeQueue_.size()))
    {
        this->purgeCancelledTimes();
    }
}

template <class TIME_STAMP>
void TimersT< TIME_STAMP >::clear(bool shouldCallCancel)
{
    int maxLoopCount = (int)timeQueue_.size();

    while (!timeQueue_.empty())
    {
        Time * pTime = timeQueue_.unsafePopBack();
        if (!pTime->isCancelled() && shouldCallCancel)
        {
            --numCancelled_;
            pTime->cancel();

            if (--maxLoopCount == 0)
            {
                shouldCallCancel = false;
            }
        }
        else if (pTime->isCancelled())
        {
            --numCancelled_;
        }

        delete pTime;
    }

    numCancelled_ = 0;
    timeQueue_ = PriorityQueue();
}

template <class TIME>
class IsNotCancelled
{
public:
    bool operator()( const TIME * pTime )
    {
        return !pTime->isCancelled();
    }
};

template <class TIME_STAMP>
void TimersT< TIME_STAMP >::purgeCancelledTimes()
{
    typename PriorityQueue::Container & container = timeQueue_.container();
    typename PriorityQueue::Container::iterator newEnd =
        std::partition( container.begin(), container.end(),
            IsNotCancelled< Time >() );

    for (typename PriorityQueue::Container::iterator iter = newEnd;
        iter != container.end();
        ++iter)
    {
        delete *iter;
    }

    const int numPurged = (int)(container.end() - newEnd);
    numCancelled_ -= numPurged;
    KBE_ASSERT( (numCancelled_ == 0) || (numCancelled_ == 1) );
    
    container.erase( newEnd, container.end() );
    timeQueue_.make_heap();
}

template <class TIME_STAMP>
int TimersT< TIME_STAMP >::process(TimeStamp now)
{
    int numFired = 0;

    while ((!timeQueue_.empty()) && (
        timeQueue_.top()->time() <= now ||
        timeQueue_.top()->isCancelled()))
    {
        Time * pTime = pProcessingNode_ = timeQueue_.top();
        timeQueue_.pop();

        if (!pTime->isCancelled())
        {
            ++numFired;
            pTime->triggerTimer();
        }

        if (!pTime->isCancelled())
        {
            timeQueue_.push( pTime );
        }
        else
        {
            delete pTime;

            KBE_ASSERT( numCancelled_ > 0 );
            --numCancelled_;
        }
    }

    pProcessingNode_ = NULL;
    lastProcessTime_ = now;
    return numFired;
}

template <class TIME_STAMP>
bool TimersT< TIME_STAMP >::legal(TimerHandle handle) const
{
    typedef Time * const * TimeIter;
    Time * pTime = static_cast< Time* >( handle.time() );

    if (pTime == NULL)
    {
        return false;
    }

    if (pTime == pProcessingNode_)
    {
        return true;
    }

    TimeIter begin = &timeQueue_.top();
    TimeIter end = begin + timeQueue_.size();

    for (TimeIter it = begin; it != end; ++it)
    {
        if (*it == pTime)
        {
            return true;
        }
    }

    return false;
}

template <class TIME_STAMP>
TIME_STAMP TimersT< TIME_STAMP >::nextExp(TimeStamp now) const
{
    if (timeQueue_.empty() ||
        now > timeQueue_.top()->time())
    {
        return 0;
    }

    return timeQueue_.top()->time() - now;
}

template <class TIME_STAMP>
bool TimersT< TIME_STAMP >::getTimerInfo( TimerHandle handle,
                    TimeStamp &         time,
                    TimeStamp &         interval,
                    void * &            pUser ) const
{
    Time * pTime = static_cast< Time * >( handle.time() );

    if (!pTime->isCancelled())
    {
        time = pTime->time();
        interval = pTime->interval();
        pUser = pTime->getUserData();

        return true;
    }

    return false;
}


inline TimeBase::TimeBase(TimersBase & owner, TimerHandler * pHandler, void * pUserData) :
    owner_(owner),
    pHandler_(pHandler),
    pUserData_(pUserData),
    state_(TIME_PENDING)
{
    pHandler->incTimerRegisterCount();
}

inline void TimeBase::cancel()
{
    if (this->isCancelled()){
        return;
    }

    KBE_ASSERT((state_ == TIME_PENDING) || (state_ == TIME_EXECUTING));
    state_ = TIME_CANCELLED;

    if (pHandler_){
        pHandler_->release(TimerHandle(this), pUserData_);
        pHandler_ = NULL;
    }

    owner_.onCancel();
}


template <class TIME_STAMP>
TimersT< TIME_STAMP >::Time::Time( TimersBase & owner,
        TimeStamp startTime, TimeStamp interval,
        TimerHandler * _pHandler, void * _pUser ) :
    TimeBase(owner, _pHandler, _pUser),
    time_(startTime),
    interval_(interval)
{
}

template <class TIME_STAMP>
void TimersT< TIME_STAMP >::Time::triggerTimer()
{
    if (!this->isCancelled())
    {
        state_ = TIME_EXECUTING;

        pHandler_->handleTimeout( TimerHandle( this ), pUserData_ );

        if ((interval_ == 0) && !this->isCancelled())
        {
            this->cancel();
        }
    }

    if (!this->isCancelled())
    {
        time_ += interval_;
        state_ = TIME_PENDING;
    }
}

转载于:https://www.cnblogs.com/dingbin1995/p/8608443.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值