微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在所有者对象的析构函数中取消asio :: steady_timer

如何解决在所有者对象的析构函数中取消asio :: steady_timer

我有一些由asio::steady_timer管理的封装逻辑。在“对象寿命真正结束”之后,无需调用此逻辑。这意味着不需要将对象寿命延长到最后一次调用计时器的完成处理程序。我可以取消对象的析构函数中的计时器,而无需等待何时调用完成处理程序吗?

#include <memory>
#include <thread>

#include <boost/asio.hpp>
#include <boost/asio/steady_timer.hpp>

namespace asio = boost::asio;

class Foo : public std::enable_shared_from_this<Foo>
{
public:
  explicit Foo(asio::io_context& ioc)
    : m_timer(ioc)
  {}

  ~Foo()
  {
    std::lock_guard<std::mutex> lock(m_mutex);
    m_timer.cancel();
  }

  void update()
  {
    std::lock_guard<std::mutex> lock(m_mutex);

    m_timer.expires_after(std::chrono::seconds(1));
    m_timer.async_wait(
      [=](const boost::system::error_code& ec)
      {
        if (!ec) {
          update();
        }
      }
    );

    // ...
  }

private:
  mutable std::mutex m_mutex;
  asio::steady_timer m_timer;
};

int main()
{
  asio::io_context ioContext;

  auto foo = std::make_shared<Foo>(ioContext);

  foo->update();

  std::thread thread(
    [&]
    {
      ioContext.run();
    }
  );

  foo.reset();

  thread.join();

  return 0;
}

更新

根据destructor,实际上不需要强制调用cancel()。因此(在上述情况下)问题是:在所有完成处理程序都被调用之前,我是否必须保持封装的steady_timer处于活动状态?

解决方法

根据我对deadline_timer的经验(但我会说它与steady timer的机制相同)-是的,您必须保持计时器对象处于活动状态,直到调用所有完成处理程序。在销毁计时器的情况下取消计时器并没有帮助,因为无法保证在销毁计时器之前将其取消。由于可以在销毁计时器对象的同时调用完成处理程序,因此可能会发生段错误。我遇到的情况是,与在Linux上相比,它在Windows上通常更可重现,因此请谨慎测试。

,

对不起,我上面的错误代码。语句“这意味着不需要延长对象寿命来最后调用计时器的完成处理程序。” 是错误的。始终应延长对象寿命,直到调用所有完成处理程序为止。

我添加了公共成员函数Foo::cancel,以便能够从外部取消预定的操作。

#include <memory>
#include <thread>

#include <boost/asio.hpp>
#include <boost/asio/steady_timer.hpp>

namespace asio = boost::asio;

class Foo : public std::enable_shared_from_this<Foo>
{
public:
  explicit Foo(asio::io_context& ioc)
    : m_timer(ioc)
  {}

  void update()
  {
    std::lock_guard<std::mutex> lock(m_mutex);

    auto self(shared_from_this());

    m_timer.expires_after(std::chrono::seconds(1));
    m_timer.async_wait(
      [this,self](const boost::system::error_code& ec)
      {
        if (!ec) {
          update();
        }
      }
    );

    // ...
  }

  void cancel()
  {
    std::lock_guard<std::mutex> lock(m_mutex);
    m_timer.cancel();
  }

private:
  mutable std::mutex m_mutex;
  asio::steady_timer m_timer;
};

int main()
{
  asio::io_context ioContext;

  auto foo = std::make_shared<Foo>(ioContext);

  foo->update();

  std::thread thread(
    [&]
    {
      ioContext.run();
    }
  );

  foo->cancel();
  foo.reset();

  thread.join();

  return 0;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。