BlackFeather'S Blog 我的技术小博 -- C/C++,Python,Golang

C++11标准stl库的timer


timer定时器,多线程,回调为阻塞模式。支持参数绑定,非常好使。


用法:

//////////////////////////////////////////////////////////////////////////
//以下是测试代码
namespace timertester
{

	class timertestclass
	{
	public:
		timertestclass(){};
		~timertestclass(){};
		void testfn()
		{
			printf("timer callback is class func.\n");
			FTimerEvent mTimer(3000, &timertestclass::threadfn, this);

			for (int i = 0; i < 5; i++)
			{
				printf("press any key to ...\n");
				getchar();
				mTimer.SetTimerEvent();
			}

			printf("stop timer \n");
			mTimer.StopTimer();
		}
		void threadf(int i)
		{
			printf("test f i:%d\n", i);
		}
		void threadfn()
		{
			printf("test fn d\n");
		}
		void threadfn2()
		{
			printf("test fn2222 \n");
		}
	};


	static void testfn1(timertestclass *cls)
	{
		cls->threadfn();
	}
	static void testpf()
	{
		printf("test printf \n");
		printf("callback ret. \n");
	}
	static void prt(int& i)
	{
		printf("print %d\n", i);
	}
	static void timertest()
	{
		int t = 0;
		FTimerEvent timerstdref(1000, prt, std::ref(t));
		for (int i = 0; i < 10; i++)
		{
			t = i;
			Sleep(1000);
		}
		timerstdref.StopTimer();

		{
			printf("timer 0 manual to set\n");
			//如果定时为0,则每次为手动触发
			FTimerEvent timerman(0, [](){
				printf("timerman in.\n");
				Sleep(5000);
				printf("timerman out.\n");
			});
			timerman.SetTimerEvent();
			timerman.SetTimerEvent();
			timerman.StopTimer();
		}

		printf("stop timer in callback\n");
		FTimerEvent timer4;
		timer4.InitTimer(1000, [](FTimerEvent *pTimer){ printf("exit timer\n"); pTimer->StopTimer(); }, &timer4);
		Sleep(3000);
		timer4.StopTimer();

		printf("set timer in callback\n");
		FTimerEvent timer5;
		timer5.InitTimer(2000, [](FTimerEvent *pTimer){
			static bool set = false;
			printf("timer in\n");
			if (!set)
			{
				printf("set timer\n");
				pTimer->SetTimerEvent();
				set = true;
			}
			printf("timer out\n");
		}, &timer5);
		Sleep(10000);
		timer5.StopTimer();

		timertestclass test1;
		test1.testfn();

		int x = 0;
		FTimerEvent timerref(1000, [&x]()
		{
			printf("x: %d \n", x);
		});
		for (int i = 0; i < 10; i++)
		{
			x = i;
			Sleep(1000);
		}
		timerref.StopTimer();

		FTimerEvent timerx(1000, [&test1]()
		{
			test1.threadfn2();
		});
		Sleep(10000);
		timerx.StopTimer();

		FTimerEvent timer0(1000, testpf);
		Sleep(10000);
		timer0.StopTimer();

		FTimerEvent timer1(1000, testfn1, &test1);
		Sleep(10000);
		timer1.StopTimer();

		FTimerEvent timer2(1000, [](){ printf("lambada no param \n"); });
		Sleep(10000);
		timer2.StopTimer();

		int param = 0;
		FTimerEvent timer3(1000, [](int *p){ printf("lambada with param: %d \n", *p); }, &param);
		Sleep(10000);
		timer3.StopTimer();

		
	}
}




Timer.h

#pragma once

#include <thread>
#include <functional>
#include <chrono>
#include <future>
#include <mutex>
#include <atomic>
#include <condition_variable>

class FTimerEvent
{
private:
	std::mutex m_mtx;
	std::condition_variable m_Condition;

	std::future<int> m_loopTask;
	std::thread::id m_loopThreadID;

	//回调函数
	std::function<void()> m_funCallback;
	//退出标记
	bool m_bExit;

	std::atomic<int> m_nManual;

	void _InitTimer(uint32_t nTimeout)
	{
		m_nManual = 0;

		m_loopTask = std::async(std::launch::async, [this, nTimeout]()->int{

			printf("timer thread start...\n");

			//保存线程ID
			m_loopThreadID = std::this_thread::get_id();
			
			while (!m_bExit || m_nManual)
			{
				//wait for timeout
				std::unique_lock<std::mutex> lock(m_mtx);
				//bool waitret = false;
				if (nTimeout)
					m_Condition.wait_for(lock, std::chrono::milliseconds(nTimeout), [this](){return (m_nManual != 0); });
				else
					m_Condition.wait(lock, [this](){return (m_nManual != 0); });

				if (m_bExit && m_nManual == 0)
					return 0;

				if (m_nManual)
					m_nManual--;

				//callback
				//printf("timer call back ... \n");
				m_funCallback();
			}

			printf("timer thread exit.\n");

			return 0;
		});

	}

public:

	//禁止拷贝和移动
	FTimerEvent(const FTimerEvent&) = delete;
	FTimerEvent& operator=(const FTimerEvent&) = delete;

	//默认的构造函数
	FTimerEvent(){ m_bExit = false; };

	//带参数的构造函数
	template<class F, class... Args>
	FTimerEvent(uint32_t dwTimeout, F&& f, Args&&... args)
	{
		m_bExit = false;

		m_funCallback = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
		_InitTimer(dwTimeout);
	}

	//如果使用默认构造函数定义的示例 可以手动初始化 不允许重复调用
	template<class F, class... Args>
	bool InitTimer(uint32_t dwTimeout, F&& f, Args&&... args)
	{
		assert(m_funCallback == nullptr);
		if (m_funCallback != nullptr)
			return false;

		m_funCallback = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
		_InitTimer(dwTimeout);

		return true;
	}

	~FTimerEvent(void)
	{
		StopTimer();

		printf("Timer has Stopped.  \n");
	}

	//阻塞事件,会等所有的回调都完成后再退出
	//如果在回调内部调用,会立即返回
	void StopTimer()
	{
		if (!m_bExit)
			printf("Stop Timer \n");

		//stop flag
		m_bExit = true;

		//通知一下阻塞事件
		if (std::this_thread::get_id() != m_loopThreadID)
		{
			m_Condition.notify_one();
			
			//等待线程退出
			try
			{
				m_loopTask.get();
			}
			catch (...){}
		}
	}


	//触发一次事件 异步返回
	//必然触发的回调,哪怕调用了StopTimer也会把Set过的次数都回调一遍再退出
	void SetTimerEvent()
	{
		m_nManual++;
		m_Condition.notify_one();
	}

};


2020年9月7日 | 发布:blackfeather | 分类:C/C++代码 | 评论:0

发表留言: