【问题标题】:boost::asio::strand::dispatch(handle) or call the handle directly?boost::asio::strand::dispatch(handle) 还是直接调用句柄?
【发布时间】:2016-07-01 03:22:21
【问题描述】:

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

strand 对象保证通过 strand 发布或调度的处理程序不会同时执行。如果可以满足保证,则可以在此函数内执行处理程序。如果这个函数是从一个通过同一个链发布或分派的处理程序中调用的,那么新的处理程序将立即执行。

所以我想知道新的handler什么时候会立即执行,为什么不直接调用而不是使用dispatch呢?

【问题讨论】:

    标签: c++ boost boost-asio


    【解决方案1】:

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

    例如,考虑这样一种情况:应用程序协议要求定期发送检测信号并响应每个检测信号请求。可以设计异步调用链,以便有两个离散的调用链:

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

           .---------------------------.
           V                           |
      keepalive::start_timer()         |
      {                                |
        timer_.expires_from_now(...);  |
        timer_.async_wait(             |
          [this](...)                  |
          {                            |
            this->start_timer();  -----'
            io.send_headerbeat();
          });
      }
      
      keepalive.start_timer();
      
    • io 类管理套接字,使用私有链序列化对套接字的访问。 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 的私有链外部调用的,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指定的handler调用顺序

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

    【讨论】:

    • 你是否使用某种(在线)工具来做 ascii 箭头?
    • @sehe 我使用asciiflow.com 快速绘制线条和形状,然后修改一些字符。
    猜你喜欢
    • 2021-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-11
    • 1970-01-01
    • 1970-01-01
    • 2022-11-30
    • 1970-01-01
    相关资源
    最近更新 更多