asio剖析(二)、添加任务-同步定时器timer
前言
关于asio同步定时器的应用,可查看之前的文章
同步定时器:https://blog.csdn.net/weijianjain/article/details/129695643?spm=1001.2014.3001.5501
本文以同步定时器深入剖析源码,了解timer是如何实现添加任务到io_io_context中,探索其中的奥秘。
一、asio定时器例子
同步定时器
#include <iostream>
#include <asio.hpp>
int main()
{
asio::io_context io;
asio::steady_timer t(io, asio::chrono::seconds(5));
t.wait();
std::cout << "asio 同步定时器." << std::endl;
return 0;
}
二、asio::io_context类
io_context类剖析链接:https://blog.csdn.net/weijianjain/article/details/129732711?spm=1001.2014.3001.5502
三、asio::steady_timer类
asio::steady_timer类声明
typedef basic_waitable_timer<chrono::steady_clock> steady_timer;
steady_timer是basic_waitable_timerchrono::steady_clock的别名,接下来我们关注basic_waitable_timerchrono::steady_clock的内容。
四、basic_waitable_timer类剖析
先来看下basic_waitable_timer类的声明
template <typename Clock,
typename WaitTraits = asio::wait_traits<Clock>
ASIO_SVC_TPARAM_DEF2(= waitable_timer_service<Clock, WaitTraits>)>
class basic_waitable_timer;
template <typename Clock, typename WaitTraits ASIO_SVC_TPARAM>
class basic_waitable_timer
: ASIO_SVC_ACCESS basic_io_object<ASIO_SVC_T>
{
public:
/// 与对象关联的执行器的类型。
typedef io_context::executor_type executor_type;
/// 时钟类型。
typedef Clock clock_type;
/// 时钟的持续时间类型。
typedef typename clock_type::duration duration;
/// 时钟的时间点类型。
typedef typename clock_type::time_point time_point;
/// 等待特征类型。
typedef WaitTraits traits_type;
/// 构造.
/**
* 此构造函数在不设置过期时间的情况下创建计时器。这个
* 必须调用expires_at()或expires_after()函数才能设置过期
* 计时器可以等待之前的时间。
*
* @param io_context计时器将用于调度的io_context对象
* 对计时器执行的任何异步操作的处理程序。
*/
explicit basic_waitable_timer(asio::io_context& io_context)
: basic_io_object<ASIO_SVC_T>(io_context)
{
}
/// 构造函数将特定的到期时间设置为绝对时间。
/**
* 此构造函数创建一个计时器并设置到期时间。
*
* @param io_context计时器将用于调度的io_context对象
* 对计时器执行的任何异步操作的处理程序。
*
* @param expiry_time用于计时器的到期时间,以
* 作为绝对时间。
*/
basic_waitable_timer(asio::io_context& io_context,
const time_point& expiry_time)
: basic_io_object<ASIO_SVC_T>(io_context)
{
asio::error_code ec;
this->get_service().expires_at(this->get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at");
}
/// 构造函数来设置相对于现在的特定到期时间。
/**
* 此构造函数创建一个计时器并设置到期时间。
*
* @param io_context计时器将用于调度的io_context对象
* 对计时器执行的任何异步操作的处理程序。
*
* @param expiry_time用于计时器的到期时间,相对于
* 现在。
*/
basic_waitable_timer(asio::io_context& io_context,
const duration& expiry_time)
: basic_io_object<ASIO_SVC_T>(io_context)
{
asio::error_code ec;
this->get_service().expires_after(
this->get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_after");
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// 拷贝构造
/**
* 此构造函数将计时器从一个对象移动到另一个对象。
*
* @param other从中移动的另一个basic_waitable_timer对象
* 发生。
*
* @note移动后,从中移动的对象处于相同的状态
* 使用@cbasic_waitable_timer(io_context&)构造函数构造。
*/
basic_waitable_timer(basic_waitable_timer&& other)
: basic_io_object<ASIO_SVC_T>(std::move(other))
{
}
/// =重载
/**
* 此赋值运算符将计时器从一个对象移动到另一个对象。取消
* 与目标对象相关联的任何未完成的异步操作。
*
* @param other从中移动的另一个basic_waitable_timer对象
* 发生。
*
* @note移动后,从中移动的对象处于相同的状态
* 使用@cbasic_waitable_timer(io_context&)构造函数构造。
*/
basic_waitable_timer& operator=(basic_waitable_timer&& other)
{
basic_io_object<ASIO_SVC_T>::operator=(std::move(other));
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// 析构
/**
* 此函数破坏计时器,取消任何未完成的异步
* 等待与计时器相关联的操作,就好像调用@cancel一样。
*/
~basic_waitable_timer()
{
}
#if defined(ASIO_ENABLE_OLD_SERVICES)
// These functions are provided by basic_io_object<>.
#else // defined(ASIO_ENABLE_OLD_SERVICES)
#if !defined(ASIO_NO_DEPRECATED)
///(已弃用:请使用get_executor()。)获取与关联的io_context
/// 对象。
/**
* 此函数可用于获取I/O
* 对象用于调度异步操作的处理程序。
*
* @return对I/O对象将使用的io_context对象的引用
* 以调度处理程序。所有权不会转移给调用者。
*/
asio::io_context& get_io_context()
{
return basic_io_object<ASIO_SVC_T>::get_io_context();
}
///(已弃用:请使用get_executor()。)获取与关联的io_context
/// 对象。
/**
* 此函数可用于获取I/O
* 对象用于调度异步操作的处理程序。
*
* @return对I/O对象将使用的io_context对象的引用
* 以调度处理程序。所有权不会转移给调用者。
*/
asio::io_context& get_io_service()
{
return basic_io_object<ASIO_SVC_T>::get_io_service();
}
#endif // !defined(ASIO_NO_DEPRECATED)
/// 获取与对象关联的执行器。
executor_type get_executor() ASIO_NOEXCEPT
{
return basic_io_object<ASIO_SVC_T>::get_executor();
}
#endif // defined(ASIO_ENABLE_OLD_SERVICES)
/// 取消所有正在等待计时器的异步操作。
/**
* 此函数强制完成任何挂起的异步等待
* 针对计时器的操作。每个取消操作的处理程序将
* 使用asio::error::operation_aborted错误代码调用。
*
* 取消计时器不会更改到期时间。
*
* @return被取消的异步操作数。
*
* @throws asio::system_error失败时抛出。
*
* @note如果调用cancel()时计时器已经过期,则
* 异步等待操作的处理程序将:
*
* @li已经被调用;或
*
* @li已排队等待在不久的将来调用。
*
* 这些处理程序不能再被取消,因此将被传递给
* 指示等待操作成功完成的错误代码。
*/
std::size_t cancel()
{
asio::error_code ec;
std::size_t s = this->get_service().cancel(this->get_implementation(), ec);
asio::detail::throw_error(ec, "cancel");
return s;
}
#if !defined(ASIO_NO_DEPRECATED)
///(已弃用:使用非error_code重载。)取消任何异步
///正在等待计时器的操作。
/**
*此函数强制完成任何挂起的异步等待
*针对计时器的操作。每个取消操作的处理程序将
*使用asio::error::operation_aborted错误代码调用。
*
*取消计时器不会更改到期时间。
*
*@param ec设置以指示发生了什么错误(如果有的话)。
*
*@return被取消的异步操作数。
*
*@note如果调用cancel()时计时器已经过期,则
*异步等待操作的处理程序将:
*
*@li已经被调用;或
*
*@li已排队等待在不久的将来调用。
*
*这些处理程序不能再被取消,因此将被传递给
*指示等待操作成功完成的错误代码。
*/
std::size_t cancel(asio::error_code& ec)
{
return this->get_service().cancel(this->get_implementation(), ec);
}
#endif // !defined(ASIO_NO_DEPRECATED)
///取消一个正在等待计时器的异步操作。
/**
*此函数强制完成一个挂起的异步等待
*针对计时器的操作。按FIFO顺序取消处理程序。这个
*已取消操作的处理程序将使用
*asio::error::operation_abored错误代码。
*
*取消计时器不会更改到期时间。
*
*@return被取消的异步操作数。也就是说,
*0或1。
*
*@throws asio::system_error失败时抛出。
*
*@note如果调用cancel_one()时计时器已经过期,那么
*异步等待操作的处理程序将:
*
*@li已经被调用;或
*
*@li已排队等待在不久的将来调用。
*
*这些处理程序不能再被取消,因此将被传递给
*指示等待操作成功完成的错误代码。
*/
std::size_t cancel_one()
{
asio::error_code ec;
std::size_t s = this->get_service().cancel_one(
this->get_implementation(), ec);
asio::detail::throw_error(ec, "cancel_one");
return s;
}
#if !defined(ASIO_NO_DEPRECATED)
///(已弃用:使用非error_code重载。)取消一个异步
///正在等待计时器的操作。
/**
*此函数强制完成一个挂起的异步等待
*针对计时器的操作。按FIFO顺序取消处理程序。这个
*已取消操作的处理程序将使用
*asio::error::operation_abored错误代码。
*
*取消计时器不会更改到期时间。
*
*@param ec设置以指示发生了什么错误(如果有的话)。
*
*@return被取消的异步操作数。也就是说,
*0或1。
*
*@note如果调用cancel_one()时计时器已经过期,那么
*异步等待操作的处理程序将:
*
*@li已经被调用;或
*
*@li已排队等待在不久的将来调用。
*
*这些处理程序不能再被取消,因此将被传递给
*指示等待操作成功完成的错误代码。
*/
std::size_t cancel_one(asio::error_code& ec)
{
return this->get_service().cancel_one(this->get_implementation(), ec);
}
///(已弃用:请使用expiry()。)获取计时器的到期时间作为绝对值
///时间。
/**
* 此功能可用于获取计时器的当前到期时间。
* 计时器是否已过期并不影响此值。
*/
time_point expires_at() const
{
return this->get_service().expires_at(this->get_implementation());
}
#endif // !defined(ASIO_NO_DEPRECATED)
///获取计时器的到期时间作为绝对时间。
/**
* 此功能可用于获取计时器的当前到期时间。
* 计时器是否已过期并不影响此值。
*/
time_point expiry() const
{
return this->get_service().expiry(this->get_implementation());
}
///将计时器的到期时间设置为绝对时间。
/**
*此函数用于设置到期时间。任何挂起的异步等待
*操作将被取消。每个取消操作的处理程序将
*使用asio::error::operation_aborted错误代码调用。
*
*@param expiry_time用于计时器的到期时间。
*
*@return被取消的异步操作数。
*
*@throws asio::system_error失败时抛出。
*
*@note如果调用expires_at()时计时器已经过期,那么
*异步等待操作的处理程序将:
*
*@li已经被调用;或
*
*@li已排队等待在不久的将来调用。
*
*这些处理程序不能再被取消,因此将被传递给
*指示等待操作成功完成的错误代码。
*/
std::size_t expires_at(const time_point& expiry_time)
{
asio::error_code ec;
std::size_t s = this->get_service().expires_at(
this->get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at");
return s;
}
#if !defined(ASIO_NO_DEPRECATED)
///将计时器的到期时间设置为绝对时间。
/**
*此函数用于设置到期时间。任何挂起的异步等待
*操作将被取消。每个取消操作的处理程序将
*使用asio::error::operation_aborted错误代码调用。
*
*@param expiry_time用于计时器的到期时间。
*
*@return被取消的异步操作数。
*
*@throws asio::system_error失败时抛出。
*
*@note如果调用expires_at()时计时器已经过期,那么
*异步等待操作的处理程序将:
*
*@li已经被调用;或
*
*@li已排队等待在不久的将来调用。
*
*这些处理程序不能再被取消,因此将被传递给
*指示等待操作成功完成的错误代码。
*/
std::size_t expires_at(const time_point& expiry_time,
asio::error_code& ec)
{
return this->get_service().expires_at(
this->get_implementation(), expiry_time, ec);
}
#endif // !defined(ASIO_NO_DEPRECATED)
///将计时器的到期时间设置为绝对时间。
/**
*此函数用于设置到期时间。任何挂起的异步等待
*操作将被取消。每个取消操作的处理程序将
*使用asio::error::operation_aborted错误代码调用。
*
*@param expiry_time用于计时器的到期时间。
*
*@return被取消的异步操作数。
*
*@throws asio::system_error失败时抛出。
*
*@note如果调用expires_at()时计时器已经过期,那么
*异步等待操作的处理程序将:
*
*@li已经被调用;或
*
*@li已排队等待在不久的将来调用。
*
*这些处理程序不能再被取消,因此将被传递给
*指示等待操作成功完成的错误代码。
*/
std::size_t expires_after(const duration& expiry_time)
{
asio::error_code ec;
std::size_t s = this->get_service().expires_after(
this->get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_after");
return s;
}
#if !defined(ASIO_NO_DEPRECATED)
///(已弃用:请使用expiry()。)获取计时器相对于现在的到期时间。
/**
*此功能可用于获取计时器的当前到期时间。
*计时器是否已过期并不影响此值。
*/
duration expires_from_now() const
{
return this->get_service().expires_from_now(this->get_implementation());
}
///(已弃用:请使用expires_after()。)设置定时器的相对到期时间
///到现在。
/**
*此函数用于设置到期时间。任何挂起的异步等待
*操作将被取消。每个取消操作的处理程序将
*使用asio::error::operation_aborted错误代码调用。
*
*@param expiry_time用于计时器的到期时间。
*
*@return被取消的异步操作数。
*
*@throws asio::system_error失败时抛出。
*
*@note如果调用expires_from_now()时计时器已经过期,
*则异步等待操作的处理程序将:
*
*@li已经被调用;或
*
*@li已排队等待在不久的将来调用。
*
*这些处理程序不能再被取消,因此将被传递给
*指示等待操作成功完成的错误代码。
*/
std::size_t expires_from_now(const duration& expiry_time)
{
asio::error_code ec;
std::size_t s = this->get_service().expires_from_now(
this->get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_from_now");
return s;
}
///(已弃用:请使用expires_after()。)设置定时器的相对到期时间
///到现在。
/**
*此函数用于设置到期时间。任何挂起的异步等待
*操作将被取消。每个取消操作的处理程序将
*使用asio::error::operation_aborted错误代码调用。
*
*@param expiry_time用于计时器的到期时间。
*
*@return被取消的异步操作数。
*
*@throws asio::system_error失败时抛出。
*
*@note如果调用expires_from_now()时计时器已经过期,
*则异步等待操作的处理程序将:
*
*@li已经被调用;或
*
*@li已排队等待在不久的将来调用。
*
*这些处理程序不能再被取消,因此将被传递给
*指示等待操作成功完成的错误代码。
*/
std::size_t expires_from_now(const duration& expiry_time,
asio::error_code& ec)
{
return this->get_service().expires_from_now(
this->get_implementation(), expiry_time, ec);
}
#endif // !defined(ASIO_NO_DEPRECATED)
///对计时器执行阻塞等待。
/**
*此功能用于等待计时器到期。此功能
*阻止并且直到定时器到期才返回。
*
*@throws asio::system_error失败时抛出。
*/
void wait()
{
asio::error_code ec;
this->get_service().wait(this->get_implementation(), ec);
asio::detail::throw_error(ec, "wait");
}
///对计时器执行阻塞等待。
/**
*此功能用于等待计时器到期。此功能
*阻止并且直到定时器到期才返回。
*
*@param ec设置以指示发生了什么错误(如果有的话)。
*/
void wait(asio::error_code& ec)
{
this->get_service().wait(this->get_implementation(), ec);
}
///在计时器上启动异步等待。
/**
*此函数可用于针对
*计时器。它总是立即返回。
*
*对于async_wait()的每次调用,将精确地调用所提供的处理程序
*一次。以下情况下将调用处理程序:
*
*@li计时器已过期。
*
*@li计时器被取消,在这种情况下会将错误传递给处理程序
*代码asio::error::operation_aborted。
*
*@param handler计时器到期时要调用的处理程序。副本
*将根据需要由处理程序组成。的函数签名
*处理程序必须是:
*@code无效处理程序(
*const asio::error_code&error//操作结果。
* ); @结束代码
*无论异步操作是立即完成还是
*否则,处理程序将不会从该函数中调用。调用
*将以与使用
*asio::io_context::post().
*/
template <typename WaitHandler>
ASIO_INITFN_RESULT_TYPE(WaitHandler,
void (asio::error_code))
async_wait(ASIO_MOVE_ARG(WaitHandler) handler)
{
//如果您在以下行中得到错误,则意味着您的处理程序发生了错误
//不满足WaitHandler的文档化类型要求。
ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
#if defined(ASIO_ENABLE_OLD_SERVICES)
return this->get_service().async_wait(this->get_implementation(),
ASIO_MOVE_CAST(WaitHandler)(handler));
#else // defined(ASIO_ENABLE_OLD_SERVICES)
async_completion<WaitHandler,
void (asio::error_code)> init(handler);
this->get_service().async_wait(this->get_implementation(),
init.completion_handler);
return init.result.get();
#endif // defined(ASIO_ENABLE_OLD_SERVICES)
}
private:
// 禁止复制和分配。
basic_waitable_timer(const basic_waitable_timer&) ASIO_DELETED;
basic_waitable_timer& operator=(
const basic_waitable_timer&) ASIO_DELETED;
};
basic_waitable_timer类保护继承于basic_io_object。
basic_waitable_timer类声明,我们在windows版本是可以看到有一个成员变量impl_,而linux下,是将其写为宏,后续对该宏的结构分析。
windows下的变量命名
detail::io_object_impl<
detail::deadline_timer_service<
detail::chrono_time_traits<Clock, WaitTraits> >,
executor_type > impl_;
linux宏声明
# define ASIO_SVC_T \
detail::deadline_timer_service< \
detail::chrono_time_traits<Clock, WaitTraits> >
他们本质上是一样的,只是声明方式不一样,本文以linux为基准剖析。
我们先来剖析下ASIO_SVC_T这个宏的定义,它在basic_waitable_timer类中是如何使用的。
以wait函数剖析
void wait(asio::error_code& ec)
{
this->get_service().wait(this->get_implementation(), ec);
}
wait函数内部的函数实现,以this->get_service()作为成员变量,使用wait(this->get_implementation(), ec)。
剖析this->get_service()
this->get_service()
this->get_service()这里的的变量在basic_io_object类里面声明
/// Get the service associated with the I/O object.
service_type& get_service()
{
return service_;
}
后面再解讲basic_io_object类
剖析wait(this->get_implementation(), ec)
wait(this->get_implementation(), ec)这个函数实际是detail::deadline_timer_service类的成员函数,detail::deadline_timer_service类在ASIO_SVC_T内声明。
剖析this->get_implementation()
this->get_implementation()也是basic_io_object类里面声明。
而detail::chrono_time_traits<Clock, WaitTraits>时间处理类,在detail::deadline_timer_service类内部使用。
五、basic_io_object类剖析
声明
class basic_io_object
{
public:
/// 将用于提供I/O操作的服务的类型。
typedef IoObjectService service_type;
/// I/O对象的基本实现类型。
typedef typename service_type::implementation_type implementation_type;
#if !defined(ASIO_NO_DEPRECATED)
///(已弃用:请使用get_executor()。)获取与关联的io_context
///对象。
/**
* 此函数可用于获取I/O
* 对象用于调度异步操作的处理程序。
*
* @return对I/O对象将使用的io_context对象的引用
* 以调度处理程序。所有权不会转移给调用者。
*/
asio::io_context& get_io_context()
{
return service_.get_io_context();
}
///(已弃用:请使用get_executor()。)获取与关联的io_context
///对象。
/**
*此函数可用于获取I/O
*对象用于调度异步操作的处理程序。
*
*@return对I/O对象将使用的io_context对象的引用
*以调度处理程序。所有权不会转移给调用者。
*/
asio::io_context& get_io_service()
{
return service_.get_io_context();
}
#endif // !defined(ASIO_NO_DEPRECATED)
/// 与对象关联的执行器的类型。
typedef asio::io_context::executor_type executor_type;
/// 获取与对象关联的执行器。
executor_type get_executor() ASIO_NOEXCEPT
{
return service_.get_io_context().get_executor();
}
protected:
///构造一个basic_io_object。
/**
* 执行:
* @code get_service().构造(get_implementation())@结束代码
*/
explicit basic_io_object(asio::io_context& io_context)
: service_(asio::use_service<IoObjectService>(io_context))
{
service_.construct(implementation_);
}
/// 析构函数,以防止通过此类型进行删除。
/**
* 执行:
* @code get_service().dedestroy(get_implementation())@结束代码
*/
~basic_io_object()
{
service_.destroy(implementation_);
}
/// 获取与I/O对象关联的服务。
service_type& get_service()
{
return service_;
}
/// 获取与I/O对象关联的服务。
const service_type& get_service() const
{
return service_;
}
/// 获取I/O对象的底层实现。
implementation_type& get_implementation()
{
return implementation_;
}
/// 获取I/O对象的底层实现。
const implementation_type& get_implementation() const
{
return implementation_;
}
private:
basic_io_object(const basic_io_object&);
basic_io_object& operator=(const basic_io_object&);
// 与I/O对象关联的服务。
service_type& service_;
/// I/O对象的底层实现。
implementation_type implementation_;
};
basic_io_object类声明实现理解不难,它主要是关联I/O对象和I/O对象底层实现
六、detail::deadline_timer_service类剖析
声明
template <typename Time_Traits>
class deadline_timer_service
: public service_base<deadline_timer_service<Time_Traits> >
{
public:
// 时间类型
typedef typename Time_Traits::time_type time_type;
// 持续时间类型。
typedef typename Time_Traits::duration_type duration_type;
//计时器的实现类型。此类型取决于定时器服务的底层实现。
struct implementation_type
: private asio::detail::noncopyable
{
time_type expiry;
bool might_have_pending_waits;
typename timer_queue<Time_Traits>::per_timer_data timer_data;
};
// 构造.
deadline_timer_service(asio::io_context& io_context)
: service_base<deadline_timer_service<Time_Traits> >(io_context),
scheduler_(asio::use_service<timer_scheduler>(io_context))
{
scheduler_.init_task();
scheduler_.add_timer_queue(timer_queue_);
}
// 析构.
~deadline_timer_service()
{
scheduler_.remove_timer_queue(timer_queue_);
}
// 销毁服务所拥有的所有用户定义的处理程序对象。
void shutdown()
{
}
// 构造一个新的定时器实现。
void construct(implementation_type& impl)
{
impl.expiry = time_type();
impl.might_have_pending_waits = false;
}
// 销毁计时器实现。
void destroy(implementation_type& impl)
{
asio::error_code ec;
cancel(impl, ec);
}
// 移动构造一个新的串行端口实现。
void move_construct(implementation_type& impl,
implementation_type& other_impl)
{
scheduler_.move_timer(timer_queue_, impl.timer_data, other_impl.timer_data);
impl.expiry = other_impl.expiry;
other_impl.expiry = time_type();
impl.might_have_pending_waits = other_impl.might_have_pending_waits;
other_impl.might_have_pending_waits = false;
}
// 从另一个串行端口实现移动分配。
void move_assign(implementation_type& impl,
deadline_timer_service& other_service,
implementation_type& other_impl)
{
if (this != &other_service)
if (impl.might_have_pending_waits)
scheduler_.cancel_timer(timer_queue_, impl.timer_data);
other_service.scheduler_.move_timer(other_service.timer_queue_,
impl.timer_data, other_impl.timer_data);
impl.expiry = other_impl.expiry;
other_impl.expiry = time_type();
impl.might_have_pending_waits = other_impl.might_have_pending_waits;
other_impl.might_have_pending_waits = false;
}
// 取消与计时器关联的任何异步等待操作。
std::size_t cancel(implementation_type& impl, asio::error_code& ec)
{
if (!impl.might_have_pending_waits)
{
ec = asio::error_code();
return 0;
}
ASIO_HANDLER_OPERATION((scheduler_.context(),
"deadline_timer", &impl, 0, "cancel"));
std::size_t count = scheduler_.cancel_timer(timer_queue_, impl.timer_data);
impl.might_have_pending_waits = false;
ec = asio::error_code();
return count;
}
// 取消与计时器关联的一个异步等待操作。
std::size_t cancel_one(implementation_type& impl,
asio::error_code& ec)
{
if (!impl.might_have_pending_waits)
{
ec = asio::error_code();
return 0;
}
ASIO_HANDLER_OPERATION((scheduler_.context(),
"deadline_timer", &impl, 0, "cancel_one"));
std::size_t count = scheduler_.cancel_timer(
timer_queue_, impl.timer_data, 1);
if (count == 0)
impl.might_have_pending_waits = false;
ec = asio::error_code();
return count;
}
// 获取计时器的到期时间作为绝对时间。
time_type expiry(const implementation_type& impl) const
{
return impl.expiry;
}
// 获取计时器的到期时间作为绝对时间。
time_type expires_at(const implementation_type& impl) const
{
return impl.expiry;
}
// 获取计时器相对于现在的到期时间。
duration_type expires_from_now(const implementation_type& impl) const
{
return Time_Traits::subtract(this->expiry(impl), Time_Traits::now());
}
// 将计时器的到期时间设置为绝对时间。
std::size_t expires_at(implementation_type& impl,
const time_type& expiry_time, asio::error_code& ec)
{
std::size_t count = cancel(impl, ec);
impl.expiry = expiry_time;
ec = asio::error_code();
return count;
}
// 设置计时器相对于现在的到期时间。
std::size_t expires_after(implementation_type& impl,
const duration_type& expiry_time, asio::error_code& ec)
{
return expires_at(impl,
Time_Traits::add(Time_Traits::now(), expiry_time), ec);
}
// 设置计时器相对于现在的到期时间。
std::size_t expires_from_now(implementation_type& impl,
const duration_type& expiry_time, asio::error_code& ec)
{
return expires_at(impl,
Time_Traits::add(Time_Traits::now(), expiry_time), ec);
}
// 对计时器执行阻塞等待。
void wait(implementation_type& impl, asio::error_code& ec)
{
time_type now = Time_Traits::now();
ec = asio::error_code();
while (Time_Traits::less_than(now, impl.expiry) && !ec)
{
this->do_wait(Time_Traits::to_posix_duration(
Time_Traits::subtract(impl.expiry, now)), ec);
now = Time_Traits::now();
}
}
// 在计时器上启动异步等待。
template <typename Handler>
void async_wait(implementation_type& impl, Handler& handler)
{
// Allocate and construct an operation to wrap the handler.
typedef wait_handler<Handler> op;
typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler);
impl.might_have_pending_waits = true;
ASIO_HANDLER_CREATION((scheduler_.context(),
*p.p, "deadline_timer", &impl, 0, "async_wait"));
scheduler_.schedule_timer(timer_queue_, impl.expiry, impl.timer_data, p.p);
p.v = p.p = 0;
}
private:
//要等待给定持续时间类型的帮助程序函数。持续时间类型应
//可以是boost::posix_time::time_duration类型,也可以实现
//其接口的必需子集。
template <typename Duration>
void do_wait(const Duration& timeout, asio::error_code& ec)
{
#if defined(ASIO_WINDOWS_RUNTIME)
std::this_thread::sleep_for(
std::chrono::seconds(timeout.total_seconds())
+ std::chrono::microseconds(timeout.total_microseconds()));
ec = asio::error_code();
#else // defined(ASIO_WINDOWS_RUNTIME)
::timeval tv;
tv.tv_sec = timeout.total_seconds();
tv.tv_usec = timeout.total_microseconds() % 1000000;
socket_ops::select(0, 0, 0, 0, &tv, ec);
#endif // defined(ASIO_WINDOWS_RUNTIME)
}
// 定时器队列
timer_queue<Time_Traits> timer_queue_;
// 安排和执行计时器的对象。通常是一个反应堆。
timer_scheduler& scheduler_;
};
detail::deadline_timer_service类实现对定时器的基本操作。
七、detail::chrono_time_traits<Clock, WaitTraits>剖析
声明·
// 用于计算最大公约数的辅助模板。
template <int64_t v1, int64_t v2>
struct gcd { enum { value = gcd<v2, v1 % v2>::value }; };
template <int64_t v1>
struct gcd<v1, 0> { enum { value = v1 }; };
// 将std::chrono时钟与截止日期计时器配合使用。
template <typename Clock, typename WaitTraits>
struct chrono_time_traits
{
// The clock type.
typedef Clock clock_type;
// The duration type of the clock.
typedef typename clock_type::duration duration_type;
// The time point type of the clock.
typedef typename clock_type::time_point time_type;
// The period of the clock.
typedef typename duration_type::period period_type;
// Get the current time.
static time_type now()
{
return clock_type::now();
}
// Add a duration to a time.
static time_type add(const time_type& t, const duration_type& d)
{
const time_type epoch;
if (t >= epoch)
{
if ((time_type::max)() - t < d)
return (time_type::max)();
}
else // t < epoch
{
if (-(t - (time_type::min)()) > d)
return (time_type::min)();
}
return t + d;
}
// Subtract one time from another.
static duration_type subtract(const time_type& t1, const time_type& t2)
{
const time_type epoch;
if (t1 >= epoch)
{
if (t2 >= epoch)
{
return t1 - t2;
}
else if (t2 == (time_type::min)())
{
return (duration_type::max)();
}
else if ((time_type::max)() - t1 < epoch - t2)
{
return (duration_type::max)();
}
else
{
return t1 - t2;
}
}
else // t1 < epoch
{
if (t2 < epoch)
{
return t1 - t2;
}
else if (t1 == (time_type::min)())
{
return (duration_type::min)();
}
else if ((time_type::max)() - t2 < epoch - t1)
{
return (duration_type::min)();
}
else
{
return -(t2 - t1);
}
}
}
// Test whether one time is less than another.
static bool less_than(const time_type& t1, const time_type& t2)
{
return t1 < t2;
}
// Implement just enough of the posix_time::time_duration interface to supply
// what the timer_queue requires.
class posix_time_duration
{
public:
explicit posix_time_duration(const duration_type& d)
: d_(d)
{
}
int64_t ticks() const
{
return d_.count();
}
int64_t total_seconds() const
{
return duration_cast<1, 1>();
}
int64_t total_milliseconds() const
{
return duration_cast<1, 1000>();
}
int64_t total_microseconds() const
{
return duration_cast<1, 1000000>();
}
private:
template <int64_t Num, int64_t Den>
int64_t duration_cast() const
{
const int64_t num1 = period_type::num / gcd<period_type::num, Num>::value;
const int64_t num2 = Num / gcd<period_type::num, Num>::value;
const int64_t den1 = period_type::den / gcd<period_type::den, Den>::value;
const int64_t den2 = Den / gcd<period_type::den, Den>::value;
const int64_t num = num1 * den2;
const int64_t den = num2 * den1;
if (num == 1 && den == 1)
return ticks();
else if (num != 1 && den == 1)
return ticks() * num;
else if (num == 1 && period_type::den != 1)
return ticks() / den;
else
return ticks() * num / den;
}
duration_type d_;
};
// Convert to POSIX duration type.
static posix_time_duration to_posix_duration(const duration_type& d)
{
return posix_time_duration(WaitTraits::to_wait_duration(d));
}
};
对时间的具体操作类。
八、同步定时器添加任务剖析
到这里我们对有一个大概的了解basic_waitable_timer类怎么使用的。
下面我们会根据同步定时器的实例来剖析,定时器是如何添加任务的。
例子:
#include <iostream>
#include <asio.hpp>
int main()
{
asio::io_context io;
asio::steady_timer t(io, asio::chrono::seconds(5));
t.wait();
std::cout << "asio 同步定时器." << std::endl;
return 0;
}
asio::steady_timer类剖析
asio::steady_timer t(io, asio::chrono::seconds(5));
asio::steady_timer类变量t,t(io, asio::chrono::seconds(5));
这里我们知道,asio::steady_timer使用
basic_waitable_timer(asio::io_context& io_context,
const duration& expiry_time);
构造。
剖析 构造函数basic_waitable_timer(asio::io_context& io_context,const duration& expiry_time);
/// 构造函数来设置相对于现在的特定到期时间。
/**
* 此构造函数创建一个计时器并设置到期时间。
*
* @param io_context计时器将用于调度的io_context对象
* 对计时器执行的任何异步操作的处理程序。
*
* @param expiry_time用于计时器的到期时间,相对于
* 现在。
*/
basic_waitable_timer(asio::io_context& io_context,
const duration& expiry_time)
: basic_io_object<ASIO_SVC_T>(io_context)
{
asio::error_code ec;
this->get_service().expires_after(
this->get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_after");
}
- 传入的asio::io_context& io_context,转换到basic_io_object<ASIO_SVC_T>里面
basic_io_object<ASIO_SVC_T>(io_context)构造剖析
basic_io_object<ASIO_SVC_T>整体声明
basic_io_object<
detail::deadline_timer_service<
detail::chrono_time_traits<Clock, WaitTraits> >,executor_type>
///构造一个basic_io_object。
/**
* 执行:
* @code get_service().构造(get_implementation())@结束代码
*/
explicit basic_io_object(asio::io_context& io_context)
: service_(asio::use_service<IoObjectService>(io_context))
{
service_.construct(implementation_);
}
service_构造
service_(asio::use_service<IoObjectService>(io_context))
追踪下asio::use_service
template <typename Service>
inline Service& use_service(io_context& ioc)
{
// Check that Service meets the necessary type requirements.
(void)static_cast<execution_context::service*>(static_cast<Service*>(0));
(void)static_cast<const execution_context::id*>(&Service::id);
return ioc.service_registry_->template use_service<Service>(ioc);
}
这里添加一个service
继续service_.construct(implementation_)剖析;构造一个新的定时器实现。该实现在deadline_timer_service类中construct函数实现。
// 构造一个新的定时器实现。
void construct(implementation_type& impl)
{
impl.expiry = time_type();
impl.might_have_pending_waits = false;
}
- expires_after剖析
this->get_service().expires_after(
this->get_implementation(), expiry_time, ec);
我们在之前第四章讲过this->get_service().wait的调用,这里的this->get_service().expires_after实际也是一样的,是detail::deadline_timer_service类的成员函数。
进入detail::deadline_timer_service类的成员函数expires_after,继续对其进行剖析
// 设置计时器相对于现在的到期时间。
std::size_t expires_after(implementation_type& impl,
const duration_type& expiry_time, asio::error_code& ec)
{
return expires_at(impl,
Time_Traits::add(Time_Traits::now(), expiry_time), ec);
}
这里看到expires_after函数内部是调用expires_at函数
// 将计时器的到期时间设置为绝对时间。
std::size_t expires_at(implementation_type& impl,
const time_type& expiry_time, asio::error_code& ec)
{
std::size_t count = cancel(impl, ec);
impl.expiry = expiry_time;
ec = asio::error_code();
return count;
}
expires_at函数是先取消与计时器关联的任何异步等待操作,再绑定expiry_time时间
// 取消与计时器关联的任何异步等待操作
std::size_t count = cancel(impl, ec);
// 绑定expiry_time时间
impl.expiry = expiry_time;
到这里asio::steady_timer类初始化完成。
继续同步定时器 t.wait();剖析
t.wait();
t.wait()函数,我们先进入到asio::steady_timer类中关于wait的实现.
///对计时器执行阻塞等待。
/**
*此功能用于等待计时器到期。此功能
*阻止并且直到定时器到期才返回。
*
*@throws asio::system_error失败时抛出。
*/
void wait()
{
asio::error_code ec;
this->get_service().wait(this->get_implementation(), ec);
asio::detail::throw_error(ec, "wait");
}
wait又回到这里了,前面讲的,wait在deadline_timer_service类中实现
// 对计时器执行阻塞等待。
void wait(implementation_type& impl, asio::error_code& ec)
{
time_type now = Time_Traits::now();
ec = asio::error_code();
while (Time_Traits::less_than(now, impl.expiry) && !ec)
{
this->do_wait(Time_Traits::to_posix_duration(
Time_Traits::subtract(impl.expiry, now)), ec);
now = Time_Traits::now();
}
}
我们看到deadline_timer_service类wait的实现,整体代码就是一个对计时器执行阻塞等待。
Time_Traits是deadline_timer_service类模板参,我们前面讲的ASIO_SVC_T宏,可以知道这里的Time_Traits是detail::chrono_time_traits类
# define ASIO_SVC_T \
detail::deadline_timer_service< \
detail::chrono_time_traits<Clock, WaitTraits> >
time_type now = Time_Traits::now();
Time_Traits::now();这函数,我们进入detail::chrono_time_traits类中找到它的实现
template <typename Clock, typename WaitTraits>
struct chrono_time_traits
{
...
// Get the current time.
static time_type now()
{
return clock_type::now();
}
...
}
clock_type是chrono_time_traits类模板参Clock,由ASIO_SVC_T宏知道是chrono::steady_clock,chrono::steady_clock是我们最开始传入的构造
asio::steady_timer t(io, asio::chrono::seconds(5));
...
typedef basic_waitable_timer<chrono::steady_clock> steady_timer;
我们看到chrono::steady_clock里面的now函数
_NODISCARD static time_point now() noexcept { // get current time
const long long _Freq = _Query_perf_frequency(); // doesn't change after system boot
const long long _Ctr = _Query_perf_counter();
static_assert(period::num == 1, "This assumes period::num == 1.");
// 10 MHz is a very common QPC frequency on modern PCs. Optimizing for
// this specific frequency can double the performance of this function by
// avoiding the expensive frequency conversion path.
constexpr long long _TenMHz = 10'000'000;
if (_Freq == _TenMHz) {
static_assert(period::den % _TenMHz == 0, "It should never fail.");
constexpr long long _Multiplier = period::den / _TenMHz;
return time_point(duration(_Ctr * _Multiplier));
} else {
// Instead of just having "(_Ctr * period::den) / _Freq",
// the algorithm below prevents overflow when _Ctr is sufficiently large.
// It assumes that _Freq * period::den does not overflow, which is currently true for nano period.
// It is not realistic for _Ctr to accumulate to large values from zero with this assumption,
// but the initial value of _Ctr could be large.
const long long _Whole = (_Ctr / _Freq) * period::den;
const long long _Part = (_Ctr % _Freq) * period::den / _Freq;
return time_point(duration(_Whole + _Part));
}
}
这里就是获取当前时间的逻辑了,不做详细剖析。
我们继续对wait函数剖析
while (Time_Traits::less_than(now, impl.expiry) && !ec)
{
this->do_wait(Time_Traits::to_posix_duration(
Time_Traits::subtract(impl.expiry, now)), ec);
now = Time_Traits::now();
}
这里的代码大致意思是:循环比对我们给定的定时时间impl.expiry与当前时间now对比,如果当前时间小于impl.expiry时间,循环继续,否则继续循环等待;
循环体:调用do_wait函数执行等待操作,我们对do_wait函数内部进行剖析,发现这里使用的是select函数阻塞等待,最后更新当前时间now。
上面讲到Time_Traits的追踪,这里Time_Traits::less_than函数,less_than函数在chrono_time_traits类中实现,比较大小
// Test whether one time is less than another.
static bool less_than(const time_type& t1, const time_type& t2)
{
return t1 < t2;
}
this->do_wait函数
//要等待给定持续时间类型的帮助程序函数。持续时间类型应
//可以是boost::posix_time::time_duration类型,也可以实现
//其接口的必需子集。
template <typename Duration>
void do_wait(const Duration& timeout, asio::error_code& ec)
{
#if defined(ASIO_WINDOWS_RUNTIME)
std::this_thread::sleep_for(
std::chrono::seconds(timeout.total_seconds())
+ std::chrono::microseconds(timeout.total_microseconds()));
ec = asio::error_code();
#else // defined(ASIO_WINDOWS_RUNTIME)
::timeval tv;
tv.tv_sec = timeout.total_seconds();
tv.tv_usec = timeout.total_microseconds() % 1000000;
socket_ops::select(0, 0, 0, 0, &tv, ec);
#endif // defined(ASIO_WINDOWS_RUNTIME)
}
Time_Traits::to_posix_duration函数,转换为POSIX持续时间类型。
// 转换为POSIX持续时间类型。
static posix_time_duration to_posix_duration(const duration_type& d)
{
return posix_time_duration(WaitTraits::to_wait_duration(d));
}
Time_Traits::subtract函数
// 从另一次中减去一次。
static duration_type subtract(const time_type& t1, const time_type& t2)
{
const time_type epoch;
if (t1 >= epoch)
{
if (t2 >= epoch)
{
return t1 - t2;
}
else if (t2 == (time_type::min)())
{
return (duration_type::max)();
}
else if ((time_type::max)() - t1 < epoch - t2)
{
return (duration_type::max)();
}
else
{
return t1 - t2;
}
}
else // t1 < epoch
{
if (t2 < epoch)
{
return t1 - t2;
}
else if (t1 == (time_type::min)())
{
return (duration_type::min)();
}
else if ((time_type::max)() - t2 < epoch - t1)
{
return (duration_type::min)();
}
else
{
return -(t2 - t1);
}
}
}
到这里我们对同步定时器的剖析就完成了。