C++11实现的定时器

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hiwubihe/article/details/84206235

分享一个基于C++11实现的定时器,当有多个定时任务时,向定时器里面添加定时任务,定时器到时间自动执行事件,编译环境(GCC) 4.7.2 ,参考代码

Timer.h

#ifndef _X_TIMER_H
#define _X_TIMER_H

#include <map>
#include <unordered_map>
#include <chrono>
#include <functional>
#include <cstdint>
#include <chrono>
#include <memory>
#include <mutex>
#include <thread>

    
typedef std::function<void(void*)> TimerEvent;
typedef std::pair<int64_t, uint32_t> TimerId;

class Timer
{
public:
    Timer(const TimerEvent& event, uint32_t ms, bool repeat,void*pUser)
        : eventCallback(event)
        , _interval(ms)
        , _isRepeat(repeat)
    	,_pUser(pUser)
    {
        if (_interval == 0)
            _interval = 1;
    }

	Timer() { }

	//定时器是否重复执行
    bool isRepeat() const 
    { 
        return _isRepeat;
    }

    static void sleep(unsigned ms) 
    { 
        std::this_thread::sleep_for(std::chrono::milliseconds(ms)); 
    }

	void setEventCallback(const TimerEvent& event)
	{
		eventCallback = event;
	}

	//直接执行任务接口
	void start(int64_t microseconds, bool repeat=false)
	{
		_isRepeat = repeat;
		auto timeBegin = std::chrono::high_resolution_clock::now();
		int64_t elapsed = 0;

		do
		{
			std::this_thread::sleep_for(std::chrono::microseconds(microseconds - elapsed));
			timeBegin = std::chrono::high_resolution_clock::now();
			eventCallback(_pUser);
			elapsed = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - timeBegin).count();
			if (elapsed < 0)
				elapsed = 0;
		} while (_isRepeat);
	}

	void stop()
	{
		_isRepeat = false;
	}

private:
	friend class TimerQueue;

	void setNextTimeout(int64_t currentTimePoint)
	{
		_nextTimeout = currentTimePoint + _interval;
	}

	int64_t getNextTimeout() const
	{
		return _nextTimeout;
	}

	//初始化为C++11—lambda函数
	TimerEvent eventCallback = [](void*){};
    bool _isRepeat = false;
    uint32_t _interval = 0;
    int64_t _nextTimeout = 0;
    void * _pUser;
};

class TimerQueue
{
public:
    TimerId addTimer(const TimerEvent& event, uint32_t ms, bool repeat,void*pUser);
    void removeTimer(TimerId timerId);

    // 返回最近一次超时的时间, 没有定时器任务返回-1
    int64_t getTimeRemaining();
    void handleTimerEvent();

private:
    int64_t getTimeNow();

    std::mutex _mutex;
    //添加定时器 MAP会自动排序 依据TimerId->first
    std::map<TimerId, std::shared_ptr<Timer>> _timers;
    //重复执行定时器列表 unordered_map 采用HASH处理 查找非常快
    std::unordered_map<uint32_t, std::shared_ptr<Timer>> _repeatTimers;
    uint32_t _lastTimerId = 0;
    uint32_t _timeRemaining = 0;
};


#endif 



Timer.cpp

#include "Timer.h"
#include <iostream>


using namespace std;
using namespace std::chrono;

TimerId TimerQueue::addTimer(const TimerEvent& event, uint32_t ms, bool repeat,void*pUser)
{
    std::lock_guard<std::mutex> locker(_mutex);

    int64_t timeoutPoint = getTimeNow();
    TimerId timerId = {timeoutPoint+ms, ++_lastTimerId};
    //相当new shared_ptr
    auto timer = make_shared<Timer>(event, ms, repeat,pUser);

    timer->setNextTimeout(timeoutPoint);

    if(repeat)
    {
    	//c++11 中添加emplace 和insert 区别时,插入不需要构造临时变量
    	//参考下面 insert
        _repeatTimers.emplace(timerId.second, timer);
    }

    _timers.insert(std::pair<TimerId,std::shared_ptr<Timer>>(timerId, std::move(timer)));

    return timerId;
}

void TimerQueue::removeTimer(TimerId timerId)
{
    std::lock_guard<std::mutex> locker(_mutex);

    auto iter = _repeatTimers.find(timerId.second);	
    if(iter != _repeatTimers.end())
    {
        TimerId t = {iter->second->getNextTimeout(), timerId.second};
        _repeatTimers.erase(iter);
        _timers.erase(t);		
    }
    else
    {
        _timers.erase(timerId);
    }
}

int64_t TimerQueue::getTimeNow()
{	
    auto timePoint = steady_clock::now();	
    return duration_cast<milliseconds>(timePoint.time_since_epoch()).count();	
}

int64_t TimerQueue::getTimeRemaining()
{	
    std::lock_guard<std::mutex> locker(_mutex);

    if(_timers.empty())
     return -1;

    //因为MAP会自动排序 所以每次所有定时任务 都是按照时间先后排列好的
    int64_t ms = _timers.begin()->first.first - getTimeNow();
    if(ms <= 0)
        return 0; 

    return ms;
}

void TimerQueue::handleTimerEvent()
{
    if(!_timers.empty() || !_repeatTimers.empty())
    {
        std::lock_guard<std::mutex> locker(_mutex);

        int64_t timePoint = getTimeNow();
        while(!_timers.empty() && _timers.begin()->first.first<=timePoint)
        {	
            _timers.begin()->second->eventCallback(_timers.begin()->second->_pUser);
            if(_timers.begin()->second->isRepeat())
            {
                _timers.begin()->second->setNextTimeout(timePoint);
                TimerId t = {_timers.begin()->second->getNextTimeout(), _timers.begin()->first.second};		
                auto timerPtr = std::move(_timers.begin()->second);			
                _timers.erase(_timers.begin());
                _timers.insert(std::pair<TimerId,std::shared_ptr<Timer>>(t, std::move(timerPtr)));

                //_timers.insert(std::pair<TimerId,std::shared_ptr<Timer>>(timerId, std::move(timer)));
            }
            else		
            {
                _timers.erase(_timers.begin());
            }
        }	
    }
}

main.cpp


#include "Timer.h"
#include <stdio.h>
#include <unistd.h>

#define USE3

#ifdef USE1
Timer g_stTimer1;
static int iCnt =0;
void TimerEvent1(void)
{

	printf("TimerEvent1 %d execute...\n",iCnt++);
	if(iCnt >= 10)
	{
		//执行10次结束
		g_stTimer1.stop();
	}
}
#endif

#ifdef USE2
void TimerEvent2(void)
{

	printf("TimerEvent2 execute...\n");
}

void TimerEvent3(void)
{

	printf("TimerEvent3 execute...\n");
}
#endif


#ifdef USE3
void TimerEventVideo(void*pVideoId)
{
	long iVideoId = (long)pVideoId;
	printf("TimerEventVideo execute id:%ld...\n",iVideoId);
}

void TimerEventAudio(void*pAudioId)
{
	long iAudioId = (long)pAudioId;
	printf("TimerEventAudio execute id:%ld...\n",iAudioId);
}
#endif


int main()
{
#ifdef USE1
	/////////用法1 BEGIN
    g_stTimer1.setEventCallback(TimerEvent1);
	//微秒单位 没过2秒执行一次 执行10次结束
	int64_t i64interval = 2000000;
	g_stTimer1.start(i64interval, true);
	printf("用法1结束\n");
	return 1;
	/////////用法1 END
#endif

#ifdef USE2
	//添加两个执行一次的定时器
	TimerQueue stTimerQueue;
	stTimerQueue.addTimer(TimerEvent2, 6000, false);
	stTimerQueue.addTimer(TimerEvent3, 1000, false);

	//距离最近下一次执行还剩多少时间
	int64_t iTimeRemain = stTimerQueue.getTimeRemaining();
	while(iTimeRemain>0)
	{
		usleep(iTimeRemain*1000);
		stTimerQueue.handleTimerEvent();
		iTimeRemain = stTimerQueue.getTimeRemaining();
	}

	//任务执行完成

	return 1;
#endif

#ifdef USE3
	//实际应用场景 音视频转发时 交替发送音视频 视频帧率25 40ms发送一帧视频
	//音频采用率44100 AAC 一帧时间(1024*1000)/44100=23ms 23ms发送一帧
	TimerQueue stTimerQueue;

	//发送第一帧视频
	printf("Send First Video Frame...\n");
	long iVedioId = 0;
	stTimerQueue.addTimer(TimerEventVideo, 40, true,(void*)iVedioId);
	//发送第一帧视频
	printf("Send First Audio Frame...\n");
	long iAudioId = 1;
	stTimerQueue.addTimer(TimerEventAudio, 23, true,(void*)iAudioId);

	//距离最近下一次执行还剩多少时间
	int64_t iTimeRemain = stTimerQueue.getTimeRemaining();
	while(iTimeRemain>0)
	{
		Timer::sleep(iTimeRemain);
		stTimerQueue.handleTimerEvent();
		iTimeRemain = stTimerQueue.getTimeRemaining();
	}

	//任务执行完成
	return 1;

#endif




}

CSDN代码下载  点击下载

猜你喜欢

转载自blog.csdn.net/hiwubihe/article/details/84206235