Boost.ASIO简要分析-2 timer实例分析

2. timer实例分析

下面分别介绍下同步操作实例与异步操作实例

2.1 同步操作实例

下面简单解释下官方文档中的定时器同步等待例子

#include <iostream>

#include <boost/asio.hpp>

#include <boost/date_time/posix_time/posix_time.hpp>

int main()

{

  boost::asio::io_service io; // 定义一个io_service对象

  boost::asio::deadline_timer t(io, boost::posix_time::seconds(5)); //定义一个deadline_timer对象,注意上面的io作为其参数。

  t.wait(); // 同步等待5秒。线程会在这边休息一小会~~

  std::cout << "Hello, world!\n";

  return 0;

}
2.2 异步操作实例

下面简单解释下官方文档中的定时器异步等待例子

#include <iostream>

#include <boost/asio.hpp>

#include <boost/date_time/posix_time/posix_time.hpp>

// 这是一个回调函数

void print(const boost::system::error_code& /*e*/)

{

  std::cout << "Hello, world!\n";

}

int main()

{

  boost::asio::io_service io;

  boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));

  t.async_wait(&print); // 这里的函数是以async开头的,表示是异步函数

  io.run(); // 因为上面调用异步函数async_wait,所以函数很快完成,并来到这里。

  return 0;

}
2.3 io_service::run分析

看到2.2的异步代码,不免会对io_service::run函数好奇。下面简要分析下。

std::size_t io_service::run()

{

  boost::system::error_code ec;

  std::size_t s = impl_.run(ec); // 主要实现代码在这句中

  boost::asio::detail::throw_error(ec);

  return s;

}

不同的平台,实现代码不一样。下面以windows环境为例。

size_t win_iocp_io_service::run(boost::system::error_code& ec)

{

// 判断是否有异步事件,没有的话就直接返回。

// 如果客户端调用异步函数(比如2.2中的t.wait()),则会调用函数 ::InterlockedIncrement(&outstanding_work_)将任务数加1。

  if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)

  {

    stop();

    ec = boost::system::error_code();

    return 0;

  }

  win_iocp_thread_info this_thread;

  thread_call_stack::context ctx(this, this_thread);

  size_t n = 0;

  while (do_one(true, ec)) // 循环调用,直到返回false

    if (n != (std::numeric_limits<size_t>::max)())

      ++n;

  return n;

}

Windows下面实现异步操作是以I/O完成端口为基础的。下面简单分析下do_one这个核心函数。省略部分非关键代码。

size_t win_iocp_io_service::do_one(bool block, boost::system::error_code& ec)

{

  for (;;)

  {

......

    // Get the next operation from the queue.

    DWORD bytes_transferred = 0;

    dword_ptr_t completion_key = 0;

    LPOVERLAPPED overlapped = 0;

    ::SetLastError(0);

    BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,

        &completion_key, &overlapped, block ? gqcs_timeout_ : 0); // 尝试从I/O完成端口读取I/O完成包。

    DWORD last_error = ::GetLastError();

    if (overlapped)

    {

      win_iocp_operation* op = static_cast<win_iocp_operation*>(overlapped);

      boost::system::error_code result_ec(last_error,

          boost::asio::error::get_system_category());

    ......

      if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1)

      {

        // Ensure the count of outstanding work is decremented on block exit.

        work_finished_on_block_exit on_exit = { this };

        (void)on_exit;

        op->complete(*this, result_ec, bytes_transferred); // 此处是关键调用

        ec = boost::system::error_code();

        return 1;

      }

    }

......

  }

}

op->complete(*this, result_ec, bytes_transferred)函数的作用就是回调之前注册的函数(如2.2中的print函数)。看下调用堆栈就更清楚了,如下图。

wps664D.tmp

posted on 2015-05-16 20:15  sudosky  阅读(555)  评论(3编辑  收藏  举报