3

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. What if at some point I want to delete my object - ioservice will try to execute already posted callbacks in destroyed object. 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.

Thanks

4

2 回答 2

7

正如 Sam 回答的那样,不可能有选择地取消已发布的处理程序。

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

另一方面,如果需要立即销毁,则考虑编写一个弱绑定到实例的函子。 这个问题讨论了与 a 的绑定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();
}

结果输出:

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

可以看出,MyClass::action()它只调用了两次:一次weak_binder是在实例还活着的时候(处理程序 A),一次boost::bind是通过实例维护的地方shared_ptr(处理程序 B)。处理程序 C 被调用,但weak_binder::operator()检测到实例已被销毁,导致静默无操作。

于 2013-08-07T17:44:04.787 回答
3

您不能通过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;
};

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

于 2013-08-06T20:10:20.110 回答