分解ASIO的async_wait

C++ May 30, 2020

async_wait

async_wait是asio的异步入口函数

socket timer stream_descriptor里面都有同样接口

和同步调用wait相比, 异步的wait复杂了很多个数量级

由于模板和宏的混合加持 导致很难理解函数的具体实现

下面来分解一下函数签名和调用流程

得益于强大的Clion和Sourcetrail...

很遗憾工作并没有变得简单

steady_timer中的定义
template <
      ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))
        WaitHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
  ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler,
      void (asio::error_code))
  async_wait(
      ASIO_MOVE_ARG(WaitHandler) handler
        ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
  {
    return async_initiate<WaitHandler, void (asio::error_code)>(
        initiate_async_wait(this), handler);
  }

下面就一个一个来解开 但首先要了解的是:

并不是所有的宏输入都输出了结果进行类型推断或计算

ASIO_COMPLETION_TOKEN_FOR

  • ASIO_COMPLETION_TOKEN_FOR(s)其实只是一个typename
#define ASIO_COMPLETION_TOKEN_FOR(s) typename

ASIO_DEFAULT_COMPLETION_TOKEN_TYPE

这个宏有点复杂 需要慢慢展开

#define ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type) \
  = typename ::asio::default_completion_token<executor_type>::type

首先executor_type 由 Executor定义

template <typename Clock, typename WaitTraits, typename Executor>
class basic_waitable_timer
{
public:
  /// The type of the executor associated with the object.
  typedef Executor executor_type;
  // .....
}

在basic_waitable_timer的前向声明中定义了默认的Executor

// Forward declaration with defaulted arguments.
template <typename Clock,
    typename WaitTraits = asio::wait_traits<Clock>,
    typename Executor = executor>
class basic_waitable_timer;

所以Executor也就是asio::executor

asio::executor是一个多态虚基类的wrapper

由成员impl_base* impl_实现

impl_base具体实现如下:

又是这种用模板子类实现的多态 跟shared_ptr的deleter差不多
// Default polymorphic allocator implementation.
template <typename Executor, typename Allocator>
class executor::impl {...}

asio::default_completion_token则为一个空类

继承自asio::default_completion_token_impl

template <typename T, typename = void>
struct default_completion_token_impl
{
  typedef void type;
};

可以看到 ::asio::default_completion_token<asio::executor>::type

其实就是void

WaitHandler默认类型为void

因为WaitHandler是传入的handler

目前看来好像 void在这里并没有什么卵用

模版定义可直接改成

template <typename WaitHandler>

ASIO_INITFN_AUTO_RESULT_TYPE

模版定义分析完,下面分析返回类型

# define ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \
  ASIO_INITFN_RESULT_TYPE(ct, sig)
  
# define ASIO_INITFN_RESULT_TYPE(ct, sig) \
  typename ::asio::async_result< \
    typename ::asio::decay<ct>::type, sig>::return_type

可以看到 最终的返回类型为

typename ::asio::async_result< \
        typename ::asio::decay<WaitHandler>::type, 
        void (asio::error_code)>::return_type

async_result的定义可以看到

template <typename CompletionToken, ASIO_COMPLETION_SIGNATURE Signature>
class async_result
{
public:
  /// The concrete completion handler type for the specific signature.
  typedef CompletionToken completion_handler_type;

  /// The return type of the initiating function.
  typedef void return_type;
	
  // ....  
}

return_type 也就是void类型

下面分析参数

  • ASIO_MOVE_ARG

参数展开后为:

const WaitHandler& handler
  • ASIO_DEFAULT_COMPLETION_TOKEN

参数展开后为

#define ASIO_DEFAULT_COMPLETION_TOKEN(e) \
  = typename ::asio::default_completion_token<e>::type()

也就是 = void()

整个函数解开后的签名为

template <typename WaitHandler>
void async_wait(const WaitHandler& handler = void())
{
	//...
}

本期先就先分析到这里

下期继续分析以下入口函数部分

async_initiate<WaitHandler, void (asio::error_code)>(
        initiate_async_wait(this), handler);

也就是

template <typename CompletionToken,
    ASIO_COMPLETION_SIGNATURE Signature,
    typename Initiation, typename... Args>
inline typename enable_if<
    detail::async_result_has_initiate_memfn<CompletionToken, Signature>::value,
    ASIO_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, Signature,
      (async_result<typename decay<CompletionToken>::type,
        Signature>::initiate(declval<ASIO_MOVE_ARG(Initiation)>(),
          declval<ASIO_MOVE_ARG(CompletionToken)>(),
          declval<ASIO_MOVE_ARG(Args)>()...)))>::type
async_initiate(ASIO_MOVE_ARG(Initiation) initiation,
    ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token,
    ASIO_MOVE_ARG(Args)... args)
{
  return async_result<typename decay<CompletionToken>::type,
    Signature>::initiate(ASIO_MOVE_CAST(Initiation)(initiation),
      ASIO_MOVE_CAST(CompletionToken)(token),
      ASIO_MOVE_CAST(Args)(args)...);
}
Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.