2013-08-06 31 views
2

我怎样才能取消已经发布的回调:如何取消升压ASIO io_service对象后

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

,并保持其他贴回调不变?

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

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

由于

回答

2

通过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队列中。

+0

好吧,我看,那么如何删除所有回调? – Artem

+0

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

+0

@Artem请用这个新信息编辑你的问题,你没有提到你的原始问题中的线程或删除对象。 –

5

正如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() 
MyClass::action() 
MyClass::action() 
~MyClass() 
weak_binder::operator()

如可以观察到,MyClass::action()仅调用两次:一次通过weak_binder而实例处于活动状态(处理程序A),并且一旦通过boost::bind,实例通过shared_ptr(处理程序B)进行维护。处理程序C被调用,但weak_binder::operator()检测到实例已被销毁,导致无声操作。