Boost C++ 库

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

Timer.3 - 将参数绑定到完成处理程序 - Boost C++ 函数库
PrevUpHomeNext

在本教程中,我们将修改 Timer.2 教程中的程序,使其计时器每秒触发一次。这将展示如何将其他参数传递给处理程序函数。

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

要使用 asio 实现重复计时器,您需要在完成处理程序中更改计时器的到期时间,然后启动新的异步等待。显然,这意味着完成处理程序需要能够访问计时器对象。为此,我们向 print 函数添加了两个新参数:

  • 指向计时器对象的指针;以及
  • 一个计数器,以便在计时器第六次触发时停止程序

在参数列表的末尾。

void print(const boost::system::error_code& /*e*/,
    boost::asio::steady_timer* t, int* count)
{

如上所述,本教程程序使用计数器在计时器第六次触发时停止运行。但是您会注意到,没有显式调用要求 io_context 停止。回想一下,在 Timer.2 教程中,我们了解到 boost::asio::io_context::run() 函数在没有更多“工作”可做时完成。通过在 count 达到 5 时不启动新的异步等待,io_context 将会耗尽工作并停止运行。

  if (*count < 5)
  {
    std::cout << *count << std::endl;
    ++(*count);

接下来,我们将计时器的到期时间从先前的到期时间向后推迟一秒。通过相对于旧到期时间计算新到期时间,我们可以确保计时器不会因为处理程序处理过程中的任何延迟而偏离整秒标记。

    t->expires_at(t->expiry() + boost::asio::chrono::seconds(1));

然后,我们启动对计时器的新异步等待。如您所见,std::bind 函数用于将额外参数与您的完成处理程序关联起来。 steady_timer::async_wait() 函数期望一个具有 void(const boost::system::error_code&) 签名的处理程序函数(或函数对象)。绑定额外参数会将您的 print 函数转换为一个正确匹配签名的函数对象。

在此示例中,std::bind 的 boost::asio::placeholders::error 参数是传递给处理程序的错误对象的命名占位符。启动异步操作时,如果使用 std::bind,则必须仅指定与处理程序参数列表匹配的参数。在 Timer.4 教程中,您将看到如果完成处理程序不需要该参数,则可以省略此占位符。

    t->async_wait(std::bind(print,
          boost::asio::placeholders::error, t, count));
  }
}

int main()
{
  boost::asio::io_context io;

添加了一个新的 count 变量,以便在计时器第六次触发时停止程序。

  int count = 0;
  boost::asio::steady_timer t(io, boost::asio::chrono::seconds(1));

与步骤 4 一样,在从 main 调用 steady_timer::async_wait() 时,我们绑定了 print 函数所需的额外参数。

  t.async_wait(std::bind(print,
        boost::asio::placeholders::error, &t, &count));

  io.run();

最后,为了证明 count 变量正在 print 处理程序函数中使用,我们将打印出它的新值。

  std::cout << "Final count is " << count << std::endl;

  return 0;
}

请参阅 完整源代码列表

返回 教程索引

上一篇: Timer.2 - 异步使用计时器

下一篇: Timer.4 - 将成员函数用作完成处理程序


PrevUpHomeNext