事件型异步定时器

code

header

/*
* 依赖系统实现的定时器
*/

#pragma once

#include <stdint.h>
#include <mutex>
#include <stdio.h>
#include <string.h>

namespace lxz {

	// 异步事件型 抽象定时器类
	class CAbstractTimer {
	public:
		virtual ~CAbstractTimer() {}

		/*
		\brief 启动定时器;若这个定时器正在运行,再次调用则是重新以interval为周期启动
		\param interval定时周期
		\retval 0:成功;-1:失败
		*/
		virtual int32_t start(long interval) = 0;

		/*
		\brief 停止定时器
		\retval 0:成功;-1:失败
		*/
		virtual int32_t stop(void) = 0;

		/*
		\brief 读取定时器到期次数,读取完成后,内部定时器到期次数清零
		\param timeout读取延时时间,单位ms;建议为0,非阻塞方式读取
		\retval 定时器到期次数
		*/
		virtual uint64_t read_events(int32_t timeout) = 0;
	};

}

#ifdef __linux__    // 仅适用于linux系统

#include <sys/timerfd.h>
#include <poll.h>
#include <errno.h>
#include <unistd.h>

namespace lxz {

	class timer : public CAbstractTimer {
	public:
		timer();

		~timer();

		timer(const timer& that) = delete;
		timer& operator=(const timer& that) = delete;

		int32_t start(long interval) override;

		int32_t stop(void) override;

		uint64_t read_events(int32_t timeout) override;
	protected:
	private:
		int m_fd;
		long m_interval;
		std::mutex m_mutex;
	};

}
#endif // __linux__

#if ((defined WIN32) || (defined _WIN32) || (defined _WIN64)) // windows平台定时器
#include <Windows.h>

//BOOL CreateTimerQueueTimer(&timer, timerQueue, (WAITORTIMERCALLBACKFUNC)cb, &arg, 0, 1000, WT_EXECUTEDEFAULT);
//BOOL ChangeTimerQueueTimer(HANDLE hTimerQueue, HANDLE hTimer, ULONG dwDueTimer, ULONG dwPeriod);
//BOOL DeleteTimerQueueTimer(HANDLE hTimerQueue,HANDLE hTimer, HANDLE hCompletionEvent);

namespace new3s {

	class timer : public CAbstractTimer {
	public:
		timer();

		~timer();

		timer(const timer& that) = delete;
		timer& operator=(const timer& that) = delete;

		int32_t start(long interval) override;

		int32_t stop(void) override;

		uint64_t read_events(int32_t timeout) override;

		

	protected:
	private:
		// 定时器到期回调函数
		friend static void WINAPI cb(PVOID param, BOOLEAN TimerOrWaitFired) {
			if (!param) {
				return;
			}

			lxz::timer* me = (lxz::timer*)param;
			std::unique_lock<std::mutex> lock(me->m_mutexCnt);
			me->m_eventsCnt++;
		}

		HANDLE m_timerQueue = nullptr;	// 定时器队列,nullptr表示使用默认定时器队列,否则请通过CreateTimerQueue创建
		HANDLE m_timer;
		long m_interval;	// 定时周期
		uint64_t m_eventsCnt;	// 定时器到期次数
		std::mutex m_mutexCnt;	// 保护m_eventsCnt
	};

}

#endif  // WIN32 || _WIN32 || _WIN64

source

#include <ttu_timer.h>
#include <chrono>
#include <thread>

namespace lxz {

#ifdef __linux__

	timer::timer() {
		m_fd = -1;
		m_interval = -1;
	}

	timer::~timer() {
		(void)stop();
	}

	int32_t timer::start(long interval) {
		std::unique_lock<std::mutex> lock(m_mutex);
		if (interval <= 0) {
			return -1;
		}

		int ret = -1;

		if (m_fd < 0) {
			ret = timerfd_create(CLOCK_REALTIME, 0);
			if (ret == -1) {
				return -1;
			}
			m_fd = ret;
		}

		struct itimerspec tim;
		struct timespec now;

		ret = clock_gettime(CLOCK_REALTIME, &now);
		if (ret == -1) {
			close(m_fd);
			m_fd = -1;
			return -1;
		}

		tim.it_interval.tv_sec = interval;
		tim.it_interval.tv_nsec = 0;
		tim.it_value.tv_nsec = now.tv_nsec;
		tim.it_value.tv_sec = now.tv_sec;

		ret = timerfd_settime(m_fd, TFD_TIMER_ABSTIME, &tim, nullptr);
		if (ret == -1) {
			close(m_fd);
			m_fd = -1;
			return -1;
		}

		m_interval = interval;

		return 0;
	}

	int32_t timer::stop(void) {
		std::unique_lock<std::mutex> lock(m_mutex);
		if (m_fd > 0) {
			close(m_fd);
			m_fd = -1;
		}
		return 0;
	}

	uint64_t timer::read_events(int32_t timeout) {
		std::unique_lock<std::mutex> lock(m_mutex);
		struct pollfd fds;
		uint64_t cnt = 0;
		ssize_t n = 0;

		fds.fd = m_fd;
		fds.events = POLLIN;
		fds.revents = 0;
		int ret = -1;

		ret = poll(&fds, 1, timeout);   // timeout ms
		if (ret == -1) {
			// fprintf(stderr, "poll error,%s\n", strerror(errno));
			// continue;
			return 0;
		}
		if (ret == 0) {
			// fprintf(stdout, "poll return no event\n");
			// continue;
			return 0;
		}

		if ((ret == 1) && (fds.revents == POLLIN)) {
			// fprintf(stdout, "poll return read event\n");
			n = read(fds.fd, &cnt, sizeof(uint64_t));
			if (n < 0) {
				// fprintf(stderr, "read error,%s\n", strerror(errno));
				// continue;
				return 0;
			}
			if (n != sizeof(uint64_t)) {
				// fprintf(stdout, "read return not uint64_t\n");
				return 0;
			}

			return cnt;
		}

		return 0;
	}

#endif	// __linux__

#if ((defined WIN32) || (defined _WIN32) || (defined _WIN64))

	timer::timer() {
		m_timer = nullptr;
		m_interval = -1;
		m_eventsCnt = 0;
	}

	timer::~timer() {
		(void)stop();

		if (m_timer) {
			(void)WaitForSingleObject(m_timer, 0);
		}

		if (m_timerQueue) {
			(void)WaitForSingleObject(m_timerQueue, 0);
		}
	}


	int32_t timer::start(long interval) {
		std::unique_lock<std::mutex> lock(timer::m_mutexCnt);

		BOOL ret = FALSE;
		// 未创建过定时器时 初次调用start就是创建
		if (!m_timer) {
			ret = CreateTimerQueueTimer(&m_timer, // 待创建的定时器
				m_timerQueue,	// 要附加到的定时器队列,为NULL表示默认队列
				(WAITORTIMERCALLBACKFUNC)cb,	// 到期回调函数
				this, // 回调函数的参数
				0,	// 启动延时,0表示即刻启动
				(DWORD)interval,	// 定时周期
				WT_EXECUTEDEFAULT);	// 默认参数
			if (!ret) {
				//fprintf_s(stderr, "CreateTimerQueueTimer failed\n");
				return -1;
			}

			m_eventsCnt = 0;
			m_interval = interval;

			return 0;

		}
		// 已创建定时器时 再次调用start就是修改
		else {
			ret = ChangeTimerQueueTimer(m_timerQueue, m_timer, 0, interval);
			if (!ret) {
				//fprintf_s(stderr, "ChangeTimerQueueTimer failed\n");
				return -1;
			}

			m_eventsCnt = 0;
			m_interval = interval;

			return 0;
		}

		return -1;
	}

	int32_t timer::stop(void) {
		std::unique_lock<std::mutex> lock(timer::m_mutexCnt);
		m_eventsCnt = 0;
		(void)DeleteTimerQueueTimer(m_timerQueue, m_timer, NULL);	// 立即删除
		(void)WaitForSingleObject(m_timer, 0);
		m_timer = nullptr;
		return 0;
	}

	uint64_t timer::read_events(int32_t timeout) {
		std::unique_lock<std::mutex> lock(timer::m_mutexCnt);
		std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
		uint64_t ret = m_eventsCnt;
		m_eventsCnt = 0;
		return ret;
	}

#endif // WIN32 || _WIN32 || _WIN64

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值