简体   繁体   English

如何取消提升asio io_service帖子

[英]How to cancel boost asio io_service post

How can I cancel already posted callback: 如何取消已发布的回调:

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

and keep other posted callbacks untouched? 并保持其他发布的回调不受影响?

The problem is that I have some object that receives events from different thread and I post them to ioservice in order to handle events in main thread. 问题是我有一些从不同线程接收事件的对象,我将它们发布到ioservice以处理主线程中的事件。 What if at some point I want to delete my object - ioservice will try to execute already posted callbacks in destroyed object. 如果在某些时候我想要删除我的对象 - ioservice将尝试在已销毁的对象中执行已发布的回调。 And in this case I can't store any flag in object since it will be removed. 在这种情况下,我不能在对象中存储任何标志,因为它将被删除。

There is a possible solution to use enable_shared_from_this and shared_from_this() , but wondering whether another solution or not. 有一种可能的解决方案可以使用enable_shared_from_thisenable_shared_from_this shared_from_this() ,但想知道是否有其他解决方案。

Thanks 谢谢

As Sam answered, it is not possible to selectively cancel posted handlers. 正如Sam回答的那样,无法有选择地取消已发布的处理程序。

If the goal is to prevent calling a member function on an object whose lifetime has expired, then using enable_shared_from_this is the idiomatic solution. 如果目标是阻止在生命周期已过期的对象上调用成员函数,那么使用enable_shared_from_this是惯用解决方案。 One consequence of this approach is that the lifetime of the object is extended to be at least that of the handler. 这种方法的一个结果是对象的生命周期至少延伸到处理程序的生命周期。 If the object's destructor can be deferred, then consider binding the object to a handler via shared_from_this() . 如果可以延迟对象的析构函数,则考虑通过shared_from_this()将对象绑定到处理程序。

On the other hand, if destruction needs to be immediate, then consider writing a functor that weakly binds to the instance. 另一方面,如果需要立即进行破坏,那么考虑编写一个与实例弱绑定的仿函数。 This question discusses binding to a weak_ptr , and provides some research/discussion links. 这个问题讨论了与weak_ptr绑定,并提供了一些研究/讨论链接。 Here is a simplified complete example of a functor that weakly binds to an object: 这是一个与对象弱绑定的仿函数的简化完整示例:

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

And the resulting output: 结果输出:

MyClass()
weak_binder::operator()
MyClass::action()
MyClass::action()
~MyClass()
weak_binder::operator()

As can be observed, MyClass::action() is only invoked twice: once through weak_binder while the instance was alive (handler A), and once through the boost::bind where the instance is maintained via a shared_ptr (handler B). 可以看出, MyClass::action()仅被调用两次:一次通过weak_binder而实例处于活动状态(处理程序A),一次通过boost::bind ,其中实例通过shared_ptr (处理程序B)维护。 Handler C is invoked, but weak_binder::operator() detects that the instance has been destroyed, resulting in a silent no-op. 调用处理程序C,但weak_binder::operator()检测到实例已被销毁,从而产生静默无操作。

You cannot selectively cancel callbacks in such a manner through an io_service . 您无法通过io_service以这种方式有选择地取消回调。 One option is to move the logic to a higher level, such as inside of MyClass . 一种选择是将逻辑移动到更高级别,例如MyClass内部。 A sample implementation may be: 示例实现可能是:

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

This class uses a boost::shared_ptr to enforce shared ownership semantics. 此类使用boost::shared_ptr来强制执行共享所有权语义。 Doing this gurantees the object lifetime will persist as long as the callback remains in the io_service queue before being dispatched. 只要回调在调度之前保留在io_service队列中,对象生存期就会保持不变。

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

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