【问题标题】:How to cancel boost asio io_service post如何取消 boost asio io_service 帖子
【发布时间】:2013-08-07 18:26:59
【问题描述】:

如何取消已经发布的回调:

getIoService()->post(boost::bind(&MyClass::myCallback, this));

并保持其他已发布的回调不受影响?

问题是我有一些从不同线程接收事件的对象,我将它们发布到 ioservice 以便处理主线程中的事件。如果在某个时候我想删除我的对象怎么办 - ioservice 将尝试在销毁的对象中执行已发布的回调。在这种情况下,我不能在对象中存储任何标志,因为它将被删除。

有一个可能的解决方案可以使用enable_shared_from_thisshared_from_this(),但想知道是否有其他解决方案。

谢谢

【问题讨论】:

    标签: c++ post boost boost-asio


    【解决方案1】:

    您不能通过io_service 以这种方式选择性地取消回调。一种选择是将逻辑移至更高级别,例如在MyClass 内部。示例实现可能是:

    class MyClass : public boost::enable_shared_from_this<MyClass>
    {
    public:
        typedef boost::shared_ptr<MyClas> Ptr;
        static Ptr create( boost::asio::io_service& io_service ) { 
            const Ptr result( new MyClass );
            io_service.post( boost::bind(&MyClass::myCallback, result) );
            return result;
        }
    
        void myCallback() { 
            if ( _canceled ) return;
        }
    
        void cancel() { _canceled = true; }
    
    private:
        MyClass() : _canceled(false) { }
    
    private:
        bool _canceled;
    };
    

    此类使用boost::shared_ptr 来强制执行共享所有权语义。这样做可以保证只要回调在被调度之前保留在io_service 队列中,对象的生命周期就会一直存在。

    【讨论】:

    • 好的,我明白了,那么如何删除所有回调?
    • 问题是我有一些从不同线程接收事件的对象,我将它们发布到 ioservice 以便处理主线程中的事件。如果在某个时候我想删除我的对象怎么办 - ioservice 将尝试在销毁的对象中执行已经发布的回调。在这种情况下,我不能在对象中存储任何标志,因为它将被删除。
    • @Artem 请使用此新信息编辑您的问题,您没有在原始问题中提及线程或删除对象。
    【解决方案2】:

    正如 Sam 所回答的,无法选择性地取消已发布的处理程序。

    如果目标是防止在生命周期已过期的对象上调用成员函数,那么使用enable_shared_from_this 是惯用的解决方案。这种方法的一个结果是对象的生命周期被延长到至少是处理程序的生命周期。如果可以延迟对象的析构函数,则考虑通过shared_from_this() 将对象绑定到处理程序。

    另一方面,如果需要立即销毁,则考虑编写一个弱绑定到实例的函子。 This 问题讨论了与weak_ptr 的绑定,并提供了一些研究/讨论链接。这是一个弱绑定到对象的函子的简化完整示例:

    #include <iostream>
    #include <boost/asio.hpp>
    #include <boost/bind.hpp>
    #include <boost/enable_shared_from_this.hpp>
    #include <boost/make_shared.hpp>
    #include <boost/shared_ptr.hpp>
    
    /// @brief Mocked up type.
    class MyClass:
      public boost::enable_shared_from_this<MyClass>
    {
    public:
      MyClass()     { std::cout << "MyClass()"         << std::endl; }
      ~MyClass()    { std::cout << "~MyClass()"        << std::endl; }
      void action() { std::cout << "MyClass::action()" << std::endl; }
    };
    
    /// @brief weak_binder is a functor that binds a member function
    ///        to a weakly managed object instance.  I.e. this
    ///        functor will not extend the life of the instance to
    ///        which it has been bound.
    template <typename Fn,
              typename C>
    struct weak_binder
    {
    private:
      typedef typename C::element_type element_type;
    public:
    
      /// @brief Constructor.
      weak_binder(Fn& fn, C& c) : fn_(fn), c_(c)
      {}
    
      /// @brief Conditional invoke Fn if C still exists.
      void operator()()
      {
        std::cout << "weak_binder::operator()" << std::endl;
        // Create a shared pointer from the weak pointer.  If
        // succesful, then the object is still alive.
        if (boost::shared_ptr<element_type> ptr = c_.lock())
        {
          // Invoke the function on the object.
          (*ptr.*fn_)();
        }
      }
    private:
      Fn fn_;
      boost::weak_ptr<element_type> c_;
    };
    
    /// @brief Helper function to create a functor that weakly
    ///        binds to a shared object.
    template <typename Fn,
              typename C>
    weak_binder<Fn, C> weak_bind(Fn fn, C c)
    {
      return weak_binder<Fn, C>(fn, c);
    }
    
    int main()
    {
      boost::asio::io_service io_service;
      boost::shared_ptr<MyClass> my_class = boost::make_shared<MyClass>();
    
      // my_class will remain alive for this handler because a shared_ptr
      // is bound to handler B, and handler B will only be destroyed after
      // handler A has been destroyed.
      io_service.post(weak_bind(&MyClass::action,
                                my_class->shared_from_this())); // A
    
      // my_class will remain alive for this handler because it is bound
      // via a shared_ptr.
      io_service.post(boost::bind(&MyClass::action,
                                  my_class->shared_from_this())); // B
    
      // my_class will not be alive for this handler, because B will have
      // been destroyed, and the my_class is reset before invoking the
      // io_service.
      io_service.post(weak_bind(&MyClass::action,
                                my_class->shared_from_this())); // C
    
      // Reset the shared_ptr, resulting in the only remaining shared_ptr
      // instance for my_class residing within handler B.
      my_class.reset();
      io_service.run();
    }
    

    结果输出:

    MyClass()
    weak_binder::operator()
    我的类::action()
    我的类::action()
    〜我的班级()
    weak_binder::operator()

    可以观察到,MyClass::action() 只被调用了两次:一次通过 weak_binder,而实例还活着(处理程序 A),一次通过 boost::bind,其中实例通过 shared_ptr 维护(处理程序乙)。处理程序 C 被调用,但 weak_binder::operator() 检测到实例已被销毁,导致静默无操作。

    【讨论】:

      猜你喜欢
      • 2015-04-22
      • 1970-01-01
      • 1970-01-01
      • 2011-06-16
      • 2019-01-22
      • 2017-09-17
      • 1970-01-01
      • 2012-11-26
      • 2011-12-18
      相关资源
      最近更新 更多