Boost.Asio:为什么定时器只执行一次?

时间:2015-12-12 19:07:16

标签: c++ c++11 boost timer boost-asio

我有一个名为 read_packet 的函数。在没有连接请求或发出计时器信号时,此功能仍然被阻止。

代码如下:

    std::size_t read_packet(const std::chrono::milliseconds& timeout,
                            boost::system::error_code& error)
    {
      // m_timer_ --> boost::asio::high_resolution_timer

      if(!m_is_first_time_) {
        m_is_first_time = true;

        // Set an expiry time relative to now.
        m_timer_.expires_from_now( timeout );
      } else {
        m_timer_.expires_at( m_timer_.expires_at() + timeout );
      }

      // Start an asynchronous wait.
      m_timer_.async_wait(
          [ this ](const boost::system::error_code& error){
            if(!error) m_is_timeout_signaled_ = true;
          }
      );

      auto result = m_io_service_.run_one();

      if( !m_is_timeout_signaled_ ) {
        m_timer_.cancel();
      }

      m_io_service_.reset();

      return result;
    }

该功能在未收到连接请求时正常工作。所有接受请求都是异步的。

接受连接后, run_one()功能不会在计时器设置的时间内被阻止。该函数始终返回1(已处理一个句柄)。该句柄对应于计时器。

我不明白为什么会出现这种情况。

为什么函数没有被阻止计时器所需的时间?

干杯。

注意:此功能用于循环。

更新

我有自己的io_service::run()功能。此功能执行其他操作和任务。我想在一段时间内监听并处理网络级别:

  • 如果网络级别出现问题,io_service::run_one()会返回, read_packet()会将控件返回到 run()函数。

  • 否则,计时器被触发, read_packet()将控件返回到 run()函数。

来自网络级别的所有内容都存储在数据结构中。然后我的 run()函数对该数据结构进行操作。 它还运行其他选项。

    void run(duration timeout, boost::system::error_code& error)
    {
      time_point start = clock_type::now();
      time_point deadline = start + timeout;

        while( !stop() ) {
          read_packet(timeout, error);
          if(error) return;

          if(is_timeout_expired( start, deadline, timeout )) return;

          // processing network level

          // other actions
        }
    }

就我而言,套接字始终处于活动状态,直到客户端请求关闭连接。

在一个时间段内,您可以管理网络级别,也可以管理其他插槽。

2 个答案:

答案 0 :(得分:0)

在仔细阅读问题之后,我意识到你实际上是在尝试使用Asio来获取同步IO,但每次读取操作都会超时。

这不是Asio的目的(因此,名称为“异步IO库”)。

但是当然,如​​果你坚持的话,你可以做到。就像我说的那样,我觉得你过于复杂。

在计时器的完成处理程序中,如果计时器已过期,则只需取消套接字操作。 (请注意,如果没有,您将获得operation_aborted,因此请检查错误代码。)

小型自我包含的例子(顺便说一句,这是你在寻求帮助时应该经常做的事情):

<强> Live On Coliru

#include <boost/asio.hpp>
#include <boost/asio/high_resolution_timer.hpp>
#include <iostream>

struct Program {

    Program() { sock_.connect({ boost::asio::ip::address_v4{}, 6771 }); }

    std::size_t read_packet(const std::chrono::milliseconds &timeout, boost::system::error_code &error) {
        m_io_service_.reset();

        boost::asio::high_resolution_timer timer { m_io_service_, timeout };

        timer.async_wait([&](boost::system::error_code) { 
                sock_.cancel();
            });

        size_t transferred = 0;
        boost::asio::async_read(sock_, boost::asio::buffer(buffer_), [&](boost::system::error_code ec, size_t tx) {
                    error       = ec;
                    transferred = tx;
                });

        m_io_service_.run();

        return transferred;
    }

  private:
    boost::asio::io_service m_io_service_;
    using tcp = boost::asio::ip::tcp;

    tcp::socket sock_{ m_io_service_ };
    std::array<char, 512> buffer_;
};

int main() {
    Program client;
    boost::system::error_code ec;

    while (!ec) {
        client.read_packet(std::chrono::milliseconds(100), ec);
    }

    std::cout << "Exited with '" << ec.message() << "'\n"; // operation canceled in case of timeout
}

如果套接字操作成功,您可以看到例如:

Exited with 'End of file'

否则,如果操作未在100毫秒内完成,则会打印:

Exited with 'Operation canceled'

另请参阅上一个答案中的await_operation,其中概括了这个模式:

答案 1 :(得分:0)

好的,代码不正确。取消定时器时,始终执行定时器处理程序。因此,if(this.myControlForm.TabPages.Contains(tabPage1)) { this.myControlForm.TabPages.Remove(tabPage1)); } if(this.myControlForm.TabPages.Contains(tabPage2)) { this.myControlForm.TabPages.Remove(tabPage2)); } [...] //similar code for other tabPages 函数永远不会被阻止。

更多信息:basic_waitable_timer::cancel

感谢您的帮助。