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


posted @ 2018-03-20 11:58  丁彬  阅读(229)  评论(0编辑  收藏  举报