如何获得boost :: asio :: io_service当前动作号

时间:2015-07-16 05:15:08

标签: c++ boost-asio

Boost :: asio :: io_service提供&#34;处理程序跟踪&#34;出于调试目的,通过定义BOOST_ASIO_ENABLE_HANDLER_TRACKING来启用它,但将其数据记录到stderr。我想在我的应用程序中使用此跟踪信息。我的问题是在我的应用程序中访问<action>的最佳方法是什么?

有关为什么的更多背景,我想这样做;我想将<action>作为参数附加到其他异步操作,以便我可以跟踪原始请求的来源。

2 个答案:

答案 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调试处理程序跟踪的示例。注意事项:

  1. 假设ioService仅从单个线程运行。我从不使用任何其他方式,所以我不确定需要改变什么来解决这个限制。
  2. std::cerr的非线程安全访问 - 将此左侧修复为练习。
  3. <强>代码

    #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