c++ - 如何取消 boost asio io_service post

标签 c++ post boost boost-asio

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

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

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

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

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

谢谢

最佳答案

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

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

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

#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() 检测到该实例已被销毁,导致静默无操作。

关于c++ - 如何取消 boost asio io_service post,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18085414/

相关文章:

c++ - 派生类的构造函数调用的函数在基类中不应该是纯虚拟的

forms - 如何在不使用 express 或 connect 的情况下使用 node.js 读取 POST 数据

c++ - boost 多边形序列化 : Ring

c++ - Visual Studio 2017 控制台应用程序 : precompiled header

c++ - 有条件的大型平面数组遍历和令人惊讶的短循环执行时间

javascript - 使用 Javascript 在服务器 URL 上发布 JSON 数据

C++ Boost 对象序列化 - 定期保存以保护数据

c++ - std::lock() 相当于 boost::shared_mutex?

c++ - 在 C++ 中使用 istringstream 时出现 "Off by one error"

java - 使用带有 @FormParam 的 POST 获取 405 "Method Not Allowed"错误(带有 Jersey REST 的 Java Web 服务)