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! "; 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! "; } 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函数)。看下调用堆栈就更清楚了,如下图。