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上面有很多,在下自认为顶多讲的也是一样的水准,就不在重复造轮子。