c++ - boost::asio::strand::dispatch(handle) 还是直接调用句柄?

标签 c++ boost boost-asio

我是 boost::asio 的新手。 boost doc说:

The strand object guarantees that handlers posted or dispatched through the strand will not be executed concurrently. The handler may be executed inside this function if the guarantee can be met. If this function is called from within a handler that was posted or dispatched through the same strand, then the new handler will be executed immediately.

所以我想知道新的处理程序何时会立即执行,为什么不直接调用它而不是使用dispatch?

最佳答案

如果调用者始终在链中运行,则可以直接调用处理程序。否则,如果调用者并不总是在链中运行,则可以使用 strand.dispatch() 来满足并发要求,同时可能优化某些调用链。

例如,考虑应用程序协议(protocol)要求定期发送心跳并响应每个心跳请求的情况。人们可以设计异步调用链,以便有两个离散的调用链:

  • keepalive 类负责定期发送心跳的调用链。它将设置一个计时器到期,到期后,设置新的到期时间并发送心跳:

         .---------------------------.
         V                           |
    keepalive::start_timer()         |
    {                                |
      timer_.expires_from_now(...);  |
      timer_.async_wait(             |
        [this](...)                  |
        {                            |
          this->start_timer();  -----'
          io.send_headerbeat();
        });
    }
    
    keepalive.start_timer();
    
  • io 类管理套接字,使用私有(private)链来序列化对套接字的访问。 io 类将从套接字读取并处理读取的数据。

        .-------------------------------------.
        V                                     |
    io::read_data()                           |
    {                                         |
      async_read(socket_, buffer_,            |
        strand_.wrap([this](...)              |
        {                                     |
          auto message = parse(buffer_);      |
          this->read_data();  ----------------'
          if (is_heartbeat_request(message))
          {
            this->send_heartbeat();
          }
        }));
    }
    
    io::start()
    {
      strand_.post([this]{ this->read_data(); });
    }
    

keepalive 的调用链中,io::send_heartbeat() 是从 io 的私有(private)链外部调用的,keepalive 无权访问。另一方面,在 io 的调用链中,io::send_heartbeat() 是从链内部调用的。如果 io::send_heartbeat() 调度将在套接字上启动写入操作的处理程序,那么它将与两个异步调用链一起正常且透明地工作。此外,当在 io 调用链中调用时,处理程序会立即执行,从而避免了发布和与链同步的开销。

io::send_heartbeat()
{
  strand_.dispatch(
    [this]()
    {
      async_write(this->socket_, ...,
        this->strand_.wrap(...));
    });
}

strand::dispatch()如果出现以下情况,将立即在当前线程中执行处理程序:

  • strand::running_in_this_thread()返回true
  • strand::running_in_this_thread() 返回 false 并且调用者正在运行 io_service 并且 strand 指定的处理程序调用顺序可以是遇见

没有公共(public) API 可以确定第二种情况的所有条件。因此,无法确定直接调用处理程序是否安全,而必须使用 strand::dispatch()

关于c++ - boost::asio::strand::dispatch(handle) 还是直接调用句柄?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38136537/

相关文章:

c++11:std::forward 的微妙之处:身份真的有必要吗?

boost - 如何将 http::response<http::string_body>::base() 转换为 std::string?

c++ - boost::asio 中的未经请求的消息使应用程序崩溃,没有 SSL 它工作正常,为什么?

c++ - 导入 DOT 文件时出现奇怪错误

c++ - boost::algorithm::contains std::vector<long> & long 值

c++ - 它如何使用 boost.asio.deadline_timer 在一个线程中完成 "async_wait"以外的其他工作

c++ - 同一程序中是否可以有两个 boost 受体?

c++ - 无限循环heisenbug : it exits if I add a printout

c++ - 读取数据文件并将每一列分配给单独的数组

c++ - 避免违反严格别名规则的最简单经验法则?