asio剖析(二)、添加任务-同步定时器timer

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);
      }
    }
  }

到这里我们对同步定时器的剖析就完成了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值