1.2.10 處理程序跟蹤
為了幫助調(diào)試異步程序,Asio提供了對(duì)處理程序跟蹤的支持瞬逊。 通過定義ASIO_ENABLE_HANDLER_TRACKING啟用時(shí),Asio將調(diào)試輸出寫入標(biāo)準(zhǔn)錯(cuò)誤流。 輸出記錄異步操作及其處理程序之間的關(guān)系理盆。
此功能在調(diào)試時(shí)非常有用,您需要知道異步操作是如何鏈接在一起的凑阶,或者是哪些待處理的異步操作猿规。 舉例來說,這里是運(yùn)行HTTP Server示例時(shí)的輸出宙橱,處理單個(gè)請(qǐng)求姨俩,然后通過Ctrl + C關(guān)閉:
@asio|1298160085.070638|0*1|signal_set@0x7fff50528f40.async_wait
@asio|1298160085.070888|0*2|socket@0x7fff50528f60.async_accept
@asio|1298160085.070913|0|resolver@0x7fff50528e28.cancel
@asio|1298160118.075438|>2|ec=asio.system:0
@asio|1298160118.075472|2*3|socket@0xb39048.async_receive
@asio|1298160118.075507|2*4|socket@0x7fff50528f60.async_accept
@asio|1298160118.075527|<2|
@asio|1298160118.075540|>3|ec=asio.system:0,bytes_transferred=122
@asio|1298160118.075731|3*5|socket@0xb39048.async_send
@asio|1298160118.075778|<3|
@asio|1298160118.075793|>5|ec=asio.system:0,bytes_transferred=156
@asio|1298160118.075831|5|socket@0xb39048.close
@asio|1298160118.075855|<5|
@asio|1298160122.827317|>1|ec=asio.system:0,signal_number=2
@asio|1298160122.827333|1|socket@0x7fff50528f60.close
@asio|1298160122.827359|<1|
@asio|1298160122.827370|>4|ec=asio.system:125
@asio|1298160122.827378|<4|
@asio|1298160122.827394|0|signal_set@0x7fff50528f40.cancel
Each line is of the form:
<tag>|<timestamp>|<action>|<description>
<tag>始終是@asio,用于標(biāo)識(shí)和提取程序輸出中的處理程序跟蹤消息师郑。
從1970年1月1日UTC開始环葵,<timestamp>是秒和微秒。
<action>采用以下形式之一:
> n程序進(jìn)入處理程序編號(hào)n宝冕。 <description>顯示處理程序的參數(shù)张遭。
<n程序離開處理程序編號(hào)n。
地梨!n由于例外菊卷,程序編號(hào)為n。
?n處理程序編號(hào)n在未被調(diào)用的情況下銷毀宝剖。 任何未完成的異步通常都是這種情況
當(dāng)io_service被銷毀時(shí)的操作的烁。
n * m處理程序編號(hào)n用完成處理程序編號(hào)m創(chuàng)建了一個(gè)新的異步操作。 <description>顯示了異步操作已啟動(dòng)诈闺。
n處理程序編號(hào)n執(zhí)行了其他一些操作渴庆。 <description>顯示了被調(diào)用的函數(shù)。 目前只
記錄close()和cancel()操作,因?yàn)檫@些操作可能會(huì)影響未決異步操作的狀態(tài)襟雷。
當(dāng)<description>顯示同步或異步操作時(shí)刃滓,格式為<object-type> @ <pointer>。<operation>耸弄。 對(duì)于處理程序輸入咧虎,它顯示一個(gè)以逗號(hào)分隔的參數(shù)列表及其值。
如上所示计呈,每個(gè)處理程序都被分配一個(gè)數(shù)字標(biāo)識(shí)符砰诵。 處理程序跟蹤輸出顯示的處理程序編號(hào)為0時(shí),表示該操作是在任何處理程序之外執(zhí)行的捌显。
視覺表示
處理程序跟蹤輸出可以使用包含的handlerviz.pl工具進(jìn)行后處理茁彭,以創(chuàng)建處理程序的可視化表示(需要GraphViz工具點(diǎn))。
1.2.11 無堆棧協(xié)程
協(xié)程類為無堆棧協(xié)程提供支持扶歪。 無堆棧協(xié)程使程序能夠以最小的開銷以同步方式實(shí)現(xiàn)異步邏輯理肺,如以下示例所示:
struct session : asio::coroutine
{
boost::shared_ptr<tcp::socket> socket_;
boost::shared_ptr<std::vector<char> > buffer_;
session(boost::shared_ptr<tcp::socket> socket)
: socket_(socket),
buffer_(new std::vector<char>(1024)){ }
void operator()(asio::error_code ec = asio::error_code(), std::size_t n = 0)
{
if (!ec) reenter (this)
{
for (;;){
yield socket_->async_read_some(asio::buffer(*buffer_), *this);
yield asio::async_write(*socket_, asio::buffer(*buffer_, n), *this);
}
}
}
};
協(xié)程類與偽關(guān)鍵字reenter,yield和fork一起使用善镰。 這些是預(yù)處理器宏妹萨,并且使用類似于Duff's Device的技術(shù)通過switch語句實(shí)現(xiàn)。 協(xié)程類的文檔提供了這些偽關(guān)鍵字的完整描述炫欺。
1.2.12 堆棧協(xié)程
spawn()函數(shù)是運(yùn)行堆棧協(xié)程的高級(jí)包裝器乎完。 它基于Boost.Coroutine庫。 spawn()函數(shù)使程序能夠以同步方式實(shí)現(xiàn)異步邏輯品洛,如以下示例所示:
asio::spawn(my_strand, do_echo);
// ...
void do_echo(asio::yield_context yield)
{
try
{
char data[128];
for (;;)
{
std::size_t length =
my_socket.async_read_some(
asio::buffer(data), yield);
asio::async_write(my_socket,
asio::buffer(data, length), yield);
}
}
catch (std::exception& e)
{
// ...
}
}
spawn()的第一個(gè)參數(shù)可能是一個(gè)strand囱怕,io_service或完成處理程序。 此參數(shù)確定允許協(xié)程執(zhí)行的上下文毫别。 例如娃弓,服務(wù)器的每個(gè)客戶端對(duì)象可能包含多個(gè)協(xié)程; 它們應(yīng)該全部運(yùn)行在同一條鏈上,以便不需要明確的同步岛宦。
第二個(gè)參數(shù)是一個(gè)帶簽名的函數(shù)對(duì)象:
void coroutine(asio::yield_context yield);
指定要作為協(xié)程的一部分運(yùn)行的代碼台丛。 可以將參數(shù)yield傳遞給異步操作來代替完成處理程序,如下所示:
std::size_t length =
my_socket.async_read_some(
asio::buffer(data), yield);
這啟動(dòng)異步操作并暫停協(xié)程砾肺。 當(dāng)異步操作完成時(shí)挽霉,協(xié)程將自動(dòng)恢復(fù)。異步操作的處理程序簽名具有以下形式:
void handler(asio::error_code ec, result_type result);
啟動(dòng)函數(shù)返回result_type变汪。 在上面的async_read_some示例中侠坎,這是size_t。 如果異步操作失敗裙盾,則error_code將轉(zhuǎn)換為system_error異常并拋出实胸。
處理器簽名的形式如下:
void handler(asio::error_code ec);
啟動(dòng)函數(shù)返回void他嫡。 如上所述,錯(cuò)誤作為system_error異常傳遞回協(xié)程庐完。 要從操作中收集error_code钢属,而不是讓它引發(fā)異常,請(qǐng)將輸出變量與yield_context關(guān)聯(lián)起來门躯,如下所示:
asio::error_code ec;
std::size_t length =
my_socket.async_read_some(
asio::buffer(data), yield[ec]);
注意:如果spawn()與Handler類型的自定義完成處理程序一起使用淆党,則函數(shù)對(duì)象簽名實(shí)際上是:
void coroutine(asio::basic_yield_context<Handler> yield);