Boost :: asio :: io_service提供&#34;处理程序跟踪&#34;出于调试目的,通过定义BOOST_ASIO_ENABLE_HANDLER_TRACKING来启用它,但将其数据记录到stderr。我想在我的应用程序中使用此跟踪信息。我的问题是在我的应用程序中访问<action>
的最佳方法是什么?
有关为什么的更多背景,我想这样做;我想将<action>
作为参数附加到其他异步操作,以便我可以跟踪原始请求的来源。
答案 0 :(得分:4)
Asio不公开其处理程序跟踪数据。尝试提取Asio中包含的跟踪信息将比滚动自定义处理程序更糟糕。
以下是Asio的handler tracking:
的摘录namespace boost {
namespace asio {
namespace detail {
class handler_tracking
{
public:
class completion;
// Base class for objects containing tracked handlers.
class tracked_handler
{
private:
// Only the handler_tracking class will have access to the id.
friend class handler_tracking;
friend class completion;
uint64_t id_;
// ...
private:
friend class handler_tracking;
uint64_t id_;
bool invoked_;
completion* next_;
};
// ...
private:
struct tracking_state;
static tracking_state* get_state();
};
} // namespace detail
} // namespace asio
} // namespace boost
正如其他人所提到的,在整个处理程序中传递GUID将允许一个人关联多个异步操作。实现此目的的一种非侵入性方法是创建自定义跟踪处理程序类型,该类型包装现有处理程序并管理跟踪数据。有关自定义处理程序的示例,请参阅Boost.Asio Invocation示例。
另外,请注意,如果使用自定义处理程序类型,则在编写处理程序时应非常小心。特别是,自定义处理程序类型的调用挂钩(asio_handler_invoke()
)可能需要考虑其他处理程序的上下文。例如,如果没有明确说明从strand::wrap()
返回的包装处理程序,那么它将阻止中间操作在组合操作的正确上下文中运行。为了避免显式处理这个问题,可以通过strand::wrap()
包装自定义处理程序:
boost::asio::async_read(..., strand.wrap(tracker.wrap(&handle_read))); // Good.
boost::asio::async_read(..., tracker.wrap(strand.wrap(&handle_read))); // Bad.
答案 1 :(得分:2)
模仿asio调试处理程序跟踪的示例。注意事项:
std::cerr
的非线程安全访问 - 将此左侧修复为练习。<强>代码强>:
#include <boost/asio.hpp>
#include <boost/atomic.hpp>
#include <iostream>
class HandlerTracking
{
public:
HandlerTracking()
:
mCount(1)
{ }
template <class Handler>
class WrappedHandler
{
public:
WrappedHandler(HandlerTracking& t, Handler h, std::uint64_t id)
:
mHandlerTracking(t),
mHandler(h),
mId(id)
{ }
WrappedHandler(const WrappedHandler& other)
:
mHandlerTracking(other.mHandlerTracking),
mHandler(other.mHandler),
mId(other.mId),
mInvoked(other.mInvoked)
{
other.mInvoked = true;
}
~WrappedHandler()
{
if (!mInvoked)
std::cerr << '~' << mId << std::endl;
}
template <class... Args>
void operator()(Args... args)
{
mHandlerTracking.mCurrHandler = mId;
std::cerr << '>' << mId << std::endl;
try
{
mInvoked = true;
mHandler(args...);
}
catch(...)
{
std::cerr << '!' << mId << std::endl;
throw;
}
std::cerr << '<' << mId << std::endl;
}
const std::uint64_t id() { return mId; }
private:
HandlerTracking& mHandlerTracking;
Handler mHandler;
const std::uint64_t mId;
mutable bool mInvoked = false;
};
template <class Handler>
WrappedHandler<Handler> wrap(Handler handler)
{
auto next = mCount.fetch_add(1);
std::cerr << mCurrHandler << '*' << next << std::endl;
return WrappedHandler<Handler>(*this, handler, next);
}
boost::atomic<std::uint64_t> mCount;
std::uint64_t mCurrHandler = 0; // Note: If ioService run on multiple threads we need a curr handler per thread
};
// Custom invokation hook for wrapped handlers
//template <typename Function, typename Handler>
//void asio_handler_invoke(Function f, HandlerTracking::WrappedHandler<Handler>* h)
//{
// std::cerr << "Context: " << h << ", " << h->id() << ", " << f.id() << std::endl;
// f();
//}
// Class to demonstrate callback with arguments
class MockSocket
{
public:
MockSocket(boost::asio::io_service& ioService) : mIoService(ioService) {}
template <class Handler>
void async_read(Handler h)
{
mIoService.post([h]() mutable { h(42); }); // we always read 42 bytes
}
private:
boost::asio::io_service& mIoService;
};
int main(int argc, char* argv[])
{
boost::asio::io_service ioService;
HandlerTracking tracking;
MockSocket socket(ioService);
std::function<void()> f1 = [&]() { std::cout << "Handler1" << std::endl; };
std::function<void()> f2 = [&]() { std::cout << "Handler2" << std::endl; ioService.post(tracking.wrap(f1)); };
std::function<void()> f3 = [&]() { std::cout << "Handler3" << std::endl; ioService.post(tracking.wrap(f2)); };
std::function<void()> f4 = [&]() { std::cout << "Handler4" << std::endl; ioService.post(tracking.wrap(f3)); };
std::function<void(int)> s1 = [](int s) { std::cout << "Socket read " << s << " bytes" << std::endl; };
socket.async_read(tracking.wrap(s1));
ioService.post(tracking.wrap(f1));
ioService.post(tracking.wrap(f2));
ioService.post(tracking.wrap(f3));
auto tmp = tracking.wrap(f4); // example handler destroyed without invocation
ioService.run();
return 0;
}
<强>输出强>:
0*1
0*2
0*3
0*4
0*5
>1
Socket read 42 bytes
<1
>2
Handler1
<2
>3
Handler2
3*6
<3
>4
Handler3
4*7
<4
>6
Handler1
<6
>7
Handler2
7*8
<7
>8
Handler1
<8
~5