c++ - 如何等待 asio 处理程序?

标签 c++ boost boost-asio synchronous c++03

我有一个围绕 boost::asio::io_service 运行的对象,它具有一些属性。类似的东西:

class Foo
{
  private:

    // Not an int in my real code, but it doesn't really matter.
    int m_bar;
    boost::asio::io_service& m_io_service;
    boost::asio::strand m_bar_strand;
};

m_bar 只能从通过链 m_bar_strand 调用的处理程序中使用。这使我不会从这些处理程序中锁定。

为了从运行 io_service::run() 的线程外部设置 m_bar 属性,我编写了一个 asynchronous_setter,如下所示:

class Foo
{
  public:
    void async_get_bar(function<void (int)> handler)
    {
      m_bar_strand.post(bind(&Foo::do_get_bar, this, handler));
    }

    void async_set_bar(int value, function<void ()> handler)
    {
      m_bar_strand.post(bind(&Foo::do_set_bar, this, value, handler));
    }

  private:

    void do_get_bar(function<void (int)> handler)
    {
      // This is only called from within the m_bar_strand, so we are safe.

      // Run the handler to notify the caller.
      handler(m_bar);
    }

    void do_set_bar(int value, function<void ()> handler)
    {
      // This is only called from within the m_bar_strand, so we are safe.
      m_bar = value;

      // Run the handler to notify the caller.
      handler();
    }

    int m_bar;
    boost::asio::io_service& m_io_service;
    boost::asio::strand m_bar_strand;
};

这非常有效,但现在我想编写一个 set_bar 的同步版本,它设置值并仅在设置有效时返回。它仍然必须保证有效集将出现在 m_bar_strand 中。理想情况下,可以重入。

我可以想象带有信号量的解决方案可以从处理程序中进行修改,但我提出的所有内容似乎都很老套而且真的不优雅。 Boost/Boost Asio 中有什么允许这样的事情吗?

您将如何着手实现此方法?

最佳答案

如果你需要同步等待一个值被设置,那么Boost.Thread的futures可能会提供一个优雅的解决方案:

The futures library provides a means of handling synchronous future values, whether those values are generated by another thread, or on a single thread in response to external stimuli, or on-demand.

简而言之,一个boost::promise创建并允许在其上设置值。稍后可以通过关联的 boost::future 检索该值.这是一个基本示例:

boost::promise<int> promise;
boost::unique_future<int> future = promise.get_future();

// start asynchronous operation that will invoke future.set_value(42)
...

assert(future.get() == 42); // blocks until future has been set.

这种方法还有两个显着的好处:

  • future 是 C++11 的一部分。
  • 异常甚至可以通过promise::set_exception() 传递给future ,支持以优雅的方式向调用者提供异常或错误。

这是一个基于原始代码的完整示例:

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>

class Foo
{
public:

  Foo(boost::asio::io_service& io_service)
    : m_io_service(io_service),
      m_bar_strand(io_service)
  {}

public:

  void async_get_bar(boost::function<void(int)> handler)
  {
    m_bar_strand.post(bind(&Foo::do_get_bar, this, handler));
  }

  void async_set_bar(int value, boost::function<void()> handler)
  {
    m_bar_strand.post(bind(&Foo::do_set_bar, this, value, handler));
  }

  int bar()
  {
    typedef boost::promise<int> promise_type;
    promise_type promise;

    // Pass the handler to async operation that will set the promise.
    void (promise_type::*setter)(const int&) = &promise_type::set_value;
    async_get_bar(boost::bind(setter, &promise, _1));

    // Synchronously wait for promise to be fulfilled.
    return promise.get_future().get();
  }

  void bar(int value)
  {
    typedef boost::promise<void> promise_type;
    promise_type promise;

    // Pass the handler to async operation that will set the promise.
    async_set_bar(value, boost::bind(&promise_type::set_value, &promise));

    // Synchronously wait for the future to finish.
    promise.get_future().wait();
  }

private:

  void do_get_bar(boost::function<void(int)> handler)
  {
    // This is only called from within the m_bar_strand, so we are safe.

    // Run the handler to notify the caller.
    handler(m_bar);
  }

  void do_set_bar(int value, boost::function<void()> handler)
  {
    // This is only called from within the m_bar_strand, so we are safe.
    m_bar = value;

    // Run the handler to notify the caller.
    handler();
  }

  int m_bar;
  boost::asio::io_service& m_io_service;
  boost::asio::strand m_bar_strand;
};

int main()
{
  boost::asio::io_service io_service;
  boost::asio::io_service::work work(io_service);
  boost::thread t(
      boost::bind(&boost::asio::io_service::run, boost::ref(io_service)));

  Foo foo(io_service);
  foo.bar(21);
  std::cout << "foo.bar is " << foo.bar() << std::endl;
  foo.bar(2 * foo.bar());
  std::cout << "foo.bar is " << foo.bar() << std::endl;

  io_service.stop();
  t.join();
}

它提供以下输出:

foo.bar is 21
foo.bar is 42

关于c++ - 如何等待 asio 处理程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20709725/

相关文章:

c++ - 有没有理由不使用单位强制类型?

c++ - 如何确保多线程 C++ 程序由多核服务器上的所有内核运行?

C++/boost::scoped_lock:缺少编译器警告

C++ boost :asio convert socket to stream?

c++ - 如何绑定(bind) SOCI 查询的输出?

c++ - 混合 C/C++ 库

c++ - opencv2模糊图像

c++ - 插入排序将数组排序到一半

c++ - 嵌套 asio 调用以 __throw_bad_function_call() 结束

c++ - 如何避免使用 Boost Asio 和 C/C++ 拒绝连接后程序退出