#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <string>
using namespace boost::asio;
void PrintSomething(const std::string& msg) {
std::cout << msg << '\n';
}
void PrintHello() {
std::cout << "Hello\n";
}
int main() {
io_service service;
service.post(PrintHello);
service.post(boost::bind(PrintSomething, "whoami"));
//service.run_one();
service.run();
return 0;
}
PrintHello函數的類型爲void (*)();
template <typename Handler>
void post(Handler handler)
{
// Allocate and construct an operation to wrap the handler.
// 生成handle_wrapper<void (*)()>對象,返回指向handle_wrapper<void (*)()>對象的指針
// 並將對象的所有權轉移給scoped_ptr智能指針對象
// 該智能指針對象如果在生命週期內沒有將對象的所有權轉移則會在析構時刪除其所指向的對象
handler_queue::scoped_ptr ptr(handler_queue::wrap(handler));
boost::asio::detail::mutex::scoped_lock lock(mutex_);
// If the service has been shut down we silently discard the handler.
if (shutdown_)
return;
// Add the handler to the end of the queue.
// handle_queue_與ptr對象同時持有指向handle_wrapper<void (*)()>對象的指針
handler_queue_.push(ptr.get());
// 將scoped_ptr對象對指針的所有權轉移給handler_queue_,保證其析構時不會釋放原來其指向的對象
ptr.release();
// An undelivered handler is treated as unfinished work.
++outstanding_work_;
// Wake up a thread to execute the handler.
if (!interrupt_one_idle_thread(lock))
{
if (!task_interrupted_ && task_)
{
task_interrupted_ = true;
task_->interrupt();
}
}
}
post方法中調用handle_queue::wrap(handler)時,編譯器會根據模板方法生成新的實例方法:
template<>
static handler* wrap(void (*)() h) {
typedef handle_wrapper<void (*)()> value_type;
typedef handle_alloc_traits<void (*)(), handle_wrapper<void (*)()> > alloc_traits;
//下面的操作將new操作分成了兩步:分配新建對象所需空間,構造對象並與空間關聯(將對象分佈到上一步所建的空間中);
// 實際上C++中的new操作都是分成這兩步。
//爲handle_wrapper<void (*)()>對象分配存儲空間
raw_handler_ptr<alloc_traits> raw_ptr(h);
//調用handle_wrapper<void (*)()>構造函數創建對象且存儲到上一步分配的空間中,並將對象的所有權轉移支handler_ptr
handler_ptr<alloc_traits> ptr(raw_ptr, h);
//返回對象指針並將對象的所有權轉移給wrap調用者
return ptr.release();
//如果不進行這一系列的所有權轉移,新生成的對象將在raw_handler_ptr或handler_ptr對象析構時釋放
}
handler_alloc_traits的定義:
template <typename Handler, typename Object>
struct handler_alloc_traits
{
typedef Handler handler_type; //函數指針對象類型
typedef Object value_type; //要創建的對象類型
typedef Object* pointer_type; //指向創建對象的指針類型
BOOST_STATIC_CONSTANT(std::size_t, value_size = sizeof(Object)); //需要創建對象的大小
};
task_io_service對象作爲io_service平臺相關的服務提供與平臺相關的run,run_one,poll,poll_one方法,其中都調用了do_one這個方法:
// do_one方法所做的主要工作:
// 通過平臺相關的系統調用(如:epoll,select)等對關心的事件進行監控
// 當關心的事件發生且處理完成,則調用其回調函數
size_t do_one(boost::asio::detail::mutex::scoped_lock& lock,
idle_thread_info* this_idle_thread, boost::system::error_code& ec)
{
// 如果沒有未完成的工作並且service沒有被用戶叫停,則立即返回,結束事件循環
// outstanding_work_(未完成的工作)由兩種類型:一種是由io_service::work封裝的工作(read, write, timer);另一種是回調
if (outstanding_work_ == 0 && !stopped_)
{
stop_all_threads(lock);
ec = boost::system::error_code();
return 0;
}
//是否採用輪詢機制
bool polling = !this_idle_thread;
bool task_has_run = false;
while (!stopped_)
{
// 處理器隊列不爲空,處理器隊列中保存兩種類型的handler:
// 一種task_handler_,在適當的時候被加入到處理器隊列,用於表示是否需要進行事件監控;
// 另一種則是事件的回調
if (!handler_queue_.empty())
{
// Prepare to execute first handler from queue.
// 準備執行處理器隊列中的第一個處理器
handler_queue::handler* h = handler_queue_.front();
// 將取出的處理器從處理器隊列中移除
handler_queue_.pop();
// 如果處理器爲task_handler_,表示需要進行事件監控處理
if (h == &task_handler_)
{
// 處理器隊列中是否有其它的處理器
bool more_handlers = (!handler_queue_.empty());
task_interrupted_ = more_handlers || polling;
// If the task has already run and we're polling then we're done.
if (task_has_run && polling)
{
task_interrupted_ = true;
handler_queue_.push(&task_handler_);
ec = boost::system::error_code();
return 0;
}
task_has_run = true;
lock.unlock();
task_cleanup c(lock, *this);
// Run the task. May throw an exception. Only block if the handler
// queue is empty and we have an idle_thread_info object, otherwise
// we want to return as soon as possible.
// 運行事件監控,參數表示是否阻塞當前線程
task_->run(!more_handlers && !polling);
}
else
{
lock.unlock();
handler_cleanup c(lock, *this);
// Invoke the handler. May throw an exception.
// 調用事件回調函數
h->invoke(); // invoke() deletes the handler object
ec = boost::system::error_code();
return 1;
}
}
else if (this_idle_thread)
{
// Nothing to run right now, so just wait for work to do.
this_idle_thread->next = first_idle_thread_;
first_idle_thread_ = this_idle_thread;
this_idle_thread->wakeup_event.clear(lock);
this_idle_thread->wakeup_event.wait(lock);
}
else
{
ec = boost::system::error_code();
return 0;
}
}
ec = boost::system::error_code();
return 0;
}