简体   繁体   English

如何获取boost :: asio :: io_service当前操作号

[英]How to get boost::asio::io_service current action number

Boost::asio::io_service provides "handler tracking" for debugging purposes, it is enabled by defining BOOST_ASIO_ENABLE_HANDLER_TRACKING but logs its data to stderr. Boost :: asio :: io_service为调试目的提供“处理程序跟踪”,它通过定义BOOST_ASIO_ENABLE_HANDLER_TRACKING启用,但将其数据记录到stderr。 I'd like to use this tracking information in my application. 我想在我的应用程序中使用此跟踪信息。 My question is what is the best way to get access to the <action> inside my application? 我的问题是访问应用程序内<action>的最佳方法是什么?

For more context as to why I want to do this; 有关我为什么要这样做的更多背景信息; I would like to attach the <action> as a parameter to other async operations so that I can track where the originating request came from. 我想将<action>作为参数附加到其他异步操作中,以便可以跟踪原始请求的来源。

Asio does not expose its handler tracking data. Asio不会公开其处理程序跟踪数据。 Attempting to extract the tracking information contained within Asio would be far more of a dirty hack than rolling ones own custom handler. 尝试提取Asio中包含的跟踪信息将比滚动自己的自定义处理程序多得多。

Here is a snippet from Asio's handler tracking : 这是Asio的处理程序跟踪的摘录:

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

As others have mentioned, passing a GUID throughout the handlers would allow one to associate multiple asynchronous operations. 正如其他人提到的那样,在整个处理程序中传递GUID将允许一个程序关联多个异步操作。 One non-intrusive way to accomplish this is to create a custom tracking handler type that wraps existing handlers and manages the tracking data. 一种非侵入式的方法是创建一个自定义跟踪处理程序类型,该类型将包装现有处理程序并管理跟踪数据。 For an example on custom handlers, see the Boost.Asio Invocation example. 有关自定义处理程序的示例,请参见Boost.Asio 调用示例。

Also, be aware that if a custom handler type is used, one should be very careful when composing handlers. 另外,请注意,如果使用自定义处理程序类型,则在编写处理程序时应格外小心。 In particular, the custom handler type's invocation hook ( asio_handler_invoke() ) may need to account for the context of other handlers. 特别是,自定义处理程序类型的调用挂钩( asio_handler_invoke() )可能需要考虑其他处理程序的上下文。 For example, if one does not explicitly account for wrapped handler returned from strand::wrap() , then it will prevent intermediate operations from running in the correct context for composed operations. 例如,如果未明确说明从strand::wrap()返回的包装处理程序,则它将阻止中间操作在组合操作的正确上下文中运行。 To avoid having to explicitly handle this, one can wrap the custom handler by 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.

An example that mimics asio debug handler tracking. 一个模仿asio调试处理程序跟踪的示例。 Caveats: 注意事项:

  1. Assumes ioService only run from a single thread. 假定ioService仅从单个线程运行。 I never use any other way so I'm not sure what needs to change to fix this limitation. 我从不使用任何其他方式,所以我不确定需要更改什么来解决此限制。
  2. Non-thread safe access to std::cerr - fixing this left as an exercise. 非线程安全访问std::cerr将此问题作为练习进行修复。

Code : 代码

#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;
}

Output : 输出

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM