boost::asio定时器

asio

asio原本是一个独立的网络库,被boost选中后,改造为Boost库的一部分。设计原则为轻继承,重组合。
符合c++的一贯风格。

基类:boost::asio::io_service
定时器类:boost::asio::basic_waitable_timer
时钟类:std::chrono::steady_clock

本文是kademlia算法的一部分,经过注释比较好理解。不准备详细讲解。

//timer.hpp
#ifndef KADEMLIA_TIMER_HPP
#define KADEMLIA_TIMER_HPP

#ifdef _MSC_VER
#pragma once
#endif

#include <map>
#include <chrono>
#include <functional>
#include <boost/asio/io_service.hpp>
#include <boost/asio/basic_waitable_timer.hpp>

namespace kademlia
{
	namespace detail {

		class timer final {

		public:

			using clock =	std::chrono::steady_clock;

			using duration = clock::duration;


		public:

			explicit timer( boost::asio::io_service & io_service);

			template < typename Callback > void expires_from_now(duration const & timeout,
				 Callback const & on_timer_expired);


		private:

			using time_point = clock::time_point;

			using callback = std::function < void ( void ) >;

			using timeouts = std::multimap < time_point, callback >;

			using deadline_timer = boost::asio::basic_waitable_timer < clock >;


		private:

			void schedule_next_tick(time_point const & expiration_time);


		private:

			deadline_timer	timer_;			// asio定时器

			timeouts		timeouts_;		// 定时任务map,排序为:从小到大排列
		};


		// 向定时器注册一个业务,执行时间点为当前时间 + timeout,执行函数为on_timer_expired
		template < typename Callback >
		void timer::expires_from_now(duration const & timeout,
			 Callback const & on_timer_expired)
		{
			auto			expiration_time = clock::now() + timeout;

			// If the current expiration time will be the sooner to expires
			// then cancel any pending wait and schedule this one instead.
			// 定时器map为空,或本次定时时间最近,则使用本次定时时间来更新asio timer、再将本次定时器加入定时器map
			if (timeouts_.empty() || expiration_time < timeouts_.begin()->first)
				schedule_next_tick(expiration_time);

			timeouts_.emplace(expiration_time, on_timer_expired);
		}

	}
}


#endif


//timer.cpp
#include "kademlia/timer.hpp"

#include "kademlia/error_impl.hpp"
#include "kademlia/log.hpp"

namespace kademlia
{
	namespace detail {

		// 构造asio定时器,io_service为asio的基类,任何对象都需要嵌入其中,一般用法是在对象构造时就指定
		timer::timer(boost::asio::io_service & io_service): timer_ {io_service}, timeouts_ {}
		{
		}

		void timer::schedule_next_tick(time_point const & expiration_time) {
			// This will cancel any pending task.
			// 设置超时时间点
			timer_.expires_at(expiration_time);

			LOG_DEBUG(timer, this) << "schedule callback at " << expiration_time.time_since_epoch().count() << "." << std::endl;

			auto			on_fire =[this] (boost::system::error_code const & failure) {
				// The current timeout has been canceled
				// hence stop right there.
				if (failure == boost::asio::error::operation_aborted)
					return;

				if (failure)
					throw std::system_error {
						make_error_code(TIMER_MALFUNCTION)
					};

				// The callbacks to execute are the first
				// n callbacks with the same keys.
				auto			begin = timeouts_.begin();
				auto			end = timeouts_.upper_bound(begin->first);

				// Call the user callbacks. 执行定时业务
				for (auto i = begin; i != end; ++i)
					i->second();

				LOG_DEBUG(timer, this) << "remove " << std::distance(begin, end) << " callback(s) scheduled at " << begin->first.time_since_epoch().count() << "." << std::endl;

				// And remove the timeout.
				timeouts_.erase(begin, end);

				// If there is a remaining timeout, schedule it.
				if (!timeouts_.empty()) {
					LOG_DEBUG(timer, this) << "schedule remaining timers" << std::endl;
					schedule_next_tick(timeouts_.begin()->first);
				}
			};

			// 异步,超时时间点到达后,执行超时任务
			timer_.async_wait(on_fire);
		}

	}
}

asio的所有对象都提供sync和async两个版本,本文中使用的async,由于是异步的方式,在定时器更新,或调度时非常方便。
关于asio的用法,csdn上面有很多,在下自认为顶多讲的也是一样的水准,就不在重复造轮子。

发布了61 篇原创文章 · 获赞 63 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/jacky128256/article/details/100670736